BUILDSNA : BANKSET 0
SNASET CPC_TYPE,4 ; modèle 6128+ conseillé
ORG #100 : RUN #100
;*** RMR2 tags + macro ***
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
struct multi
mapOffset defw
HSSR defb ; 0-12
VSSR defb ; #00-#70
colonne defb ; 0-3 dans la tuile
ligne defb ; 0-60 par pas de 4 dans la tuile
adresseDebut defw
crtc12 defb ; cache des bits de bank
crtcHL defw ; adresse CRTC
nextBuffer defw ; adresse de la structure du buffer suivant
endstruct
; définition des constantes pour le curseur
OCTET_CURSEUR_HAUT equ matriceClavier+0 : BIT_CURSEUR_HAUT equ 1
OCTET_CURSEUR_DROITE equ matriceClavier+0 : BIT_CURSEUR_DROITE equ 2
OCTET_CURSEUR_BAS equ matriceClavier+0 : BIT_CURSEUR_BAS equ 4
OCTET_CURSEUR_GAUCHE equ matriceClavier+1 : BIT_CURSEUR_GAUCHE equ 1
ld sp,#100 ; pile par défaut ailleurs qu'en #C000 car nous avons un buffer ici
ld bc,#7F00+%10001100+%00 : out (c),c ; MODE 0
call UnlockAsic : RMR2 ASICON
ld hl,palettePlus : ld de,#6400 : ld bc,32 : ldir : ld hl,#000 : ld (#6420),hl ; +border noir
ld bc,#BC00+1 : out (c),c : ld bc,#BD00+32 : out (c),c ; Notre map fait 128 pixels de large, adaptez selon VOS besoins
ld bc,#BC00+2 : out (c),c : ld bc,#BD00+42 : out (c),c ; Centrer l'écran en X
ld bc,#BC00+6 : out (c),c : ld bc,#BD00+32 : out (c),c ; Hauteur de l'écran visible en lignes de caractères
ld bc,#BC00+7 : out (c),c : ld bc,#BD00+34 : out (c),c ; Centrer l'écran en Y
ld bc,#BC00+12 : out (c),c : ld bc,#BD30 : out (c),c ; adresse par défaut
ld bc,#BC00+13 : out (c),c : ld bc,#BD00 : out (c),c
ld ix,ecran1 : ld a,#80 : ld de,ecran2 : call InitEcran
ld ix,ecran2 : ld a,#C0 : ld de,ecran1 : call InitEcran
ld ix,ecran1 ; notre structure écran par défaut pour aller scroller
LaBoucle
call lectureMatriceClavier
call UpdateHardware
ld de,(ix+multi.nextBuffer) : ld ix,de ; permuter la structure de définition du buffer
; on compense rapport à l'écran précédent
.Xnegatif ld hl,depx : ld a,(hl) : and #80 : jr z,.XpasNegatif : inc (hl) : call ScrollGauche : jr .Xnegatif
.XpasNegatif
.Xpositif ld hl,depx : ld a,(hl) : and #7F : jr z,.XpasPositif : dec (hl) : call ScrollDroite : jr .Xpositif
.XpasPositif
.Ynegatif ld hl,depy : ld a,(hl) : and #80 : jr z,.YpasNegatif : inc (hl) : call ScrollBas : jr .Ynegatif
.YpasNegatif
.Ypositif ld hl,depy : ld a,(hl) : and #7F : jr z,.YpasPositif : dec (hl) : call ScrollHaut : jr .Ypositif
.YpasPositif
ld a,(OCTET_CURSEUR_BAS) : and BIT_CURSEUR_BAS : jr nz,.noBas : call ScrollBas : ld hl,depy : dec (hl) : .noBas
ld a,(OCTET_CURSEUR_HAUT) : and BIT_CURSEUR_HAUT : jr nz,.noHaut : call ScrollHaut : ld hl,depy : inc (hl) : .noHaut
ld a,(OCTET_CURSEUR_DROITE) : and BIT_CURSEUR_DROITE : jr nz,.noDroite : call ScrollDroite : ld hl,depx : inc (hl) : .noDroite
ld a,(OCTET_CURSEUR_GAUCHE) : and BIT_CURSEUR_GAUCHE : jr nz,.noGauche : call ScrollGauche : ld hl,depx : dec (hl) : .noGauche
jp LaBoucle
lectureMatriceClavier
ld hl,matriceClavier
ld bc,#f782
out (c),c
ld bc,#f40e
ld e,b
out (c),c
ld bc,#f6c0
ld d,b
out (c),c
out (c),0
ld bc,#f792
out (c),c
ld a,#40
ld c,d
.loop ld b,d
out (c),a ; sélectionner la ligne
ld b,e
ini ; lire et stocker dans notre tableau
inc a
inc c
jr nz,.loop
ld bc,#f782
out (c),c
ret
matriceClavier defs 10,#FF
;---------------------------------------------------------------------
MACRO calculeAdresseTuile increment
exx : ld a,(hl) ; index de la tile dans A
if {increment}==0 : elseif {increment}==1 : inc hl : else : add hl,bc : endif
exx ; index de la tile dans A / HL'=tileMap
ld hl,tuiles : ld b,a : ld c,0 : srl bc : srl bc : add hl,bc ; HL=adresse du début de la tuile
MEND
MACRO calculeAdresseTuileLigne increment
calculeAdresseTuile {increment}
ld a,(ix+multi.ligne) : add l : ld l,a ; HL=adresse du début de la tuile à la bonne ligne
MEND
MACRO calculeAdresseTuileColonne increment
calculeAdresseTuile {increment}
ld a,(ix+multi.colonne) : add l : ld l,a ; HL=adresse du début de la tuile à la bonne colonne
MEND
MACRO calculeAdresseTuileLigneColonne increment
calculeAdresseTuile {increment}
ld a,(ix+multi.ligne) : add (ix+multi.colonne) : add l : ld l,a ; HL=adresse du début de la tuile à la bonne ligne ET bonne colonne
MEND
MACRO expandNextLineDE
ld a,d : add 8 : ld d,a : and #38 : jr nz,@termine
ld a,64 : add e : ld e,a : ld a,#C0 : adc d : ld d,a : res 3,d
@termine
MEND
;---------------------------------------------------------------------
ScrollGauche
;---------------------------------------------------------------------
ld a,(ix+multi.colonne) : or a : jr nz,.goForScroll
ld a,(ix+multi.mapOffset) : and 63 : ret z ; si on est sur la colonne zéro de la tile la plus à gauche... Bye!
.goForScroll
ld a,(ix+multi.HSSR) : bit 2,a : jr nz,.willDraw : add 4 : ld (ix+multi.HSSR),a : ret ; on ne change que le décalage et bye!
.willDraw
add 4 : and 15 : jr nz,.stillSSR
ld hl,(ix+multi.crtcHL) : dec hl : ld (ix+multi.crtcHL),hl ; each word
.stillSSR ld (ix+multi.HSSR),a
ld hl,(ix+multi.adresseDebut) :
ld a,h : and 7 : or l : jr nz,.skip : ld a,h : add 8 : ld h,a : .skip dec hl ; gérer le rebouclage à la décrémentation
ld (ix+multi.adresseDebut),hl
ld a,(ix+multi.colonne) : dec a : and 3 : ld (ix+multi.colonne),a : cp 3 : jr nz,.stillPosx : dec (ix+multi.mapOffset) : .stillPosx
ld hl,(ix+multi.mapOffset) : ld bc,64 : exx ; HL'=adresse de la tile BC'=saut de ligne dans la tileMap
ld de,(ix+multi.adresseDebut) ; DE=haut de la colonne à rafraichir
; accès direct à l'affichage d'une colonne
;------------------
afficheColonne
;------------------
ld a,(ix+multi.ligne) : or a : jp nz,.clipped
ld yh,16
.loopTiles
calculeAdresseTuileColonne 64
ld bc,#0804
repeat 7 : ld a,(hl) : ld (de),a : ld a,l : add c : ld l,a : ld a,d : add b : ld d,a : rend
ld a,(hl) : ld (de),a : ld a,l : add c : ld l,a
ld a,64 : add e : ld e,a : ld a,#C8 : adc d : ld d,a : res 3,d
repeat 7 : ld a,(hl) : ld (de),a : ld a,l : add c : ld l,a : ld a,d : add b : ld d,a : rend
ld a,(hl) : ld (de),a
ld a,64 : add e : ld e,a : ld a,#C8 : adc d : ld d,a : res 3,d
dec yh : jp nz,.loopTiles
ret
;----------
.clipped
calculeAdresseTuileLigneColonne 64
ld a,64 : sub (ix+multi.ligne) : rrca : rrca : and 15 : ld b,a : ld c,4
.loopColumnC1 ld a,(hl) : ld (de),a : expandNextLineDE (void) : ld a,l : add c : ld l,a : djnz .loopColumnC1
ld yh,15
call .loopTiles
; dernière tuile clippée
calculeAdresseTuileColonne 0
ld a,(ix+multi.ligne) : rrca : rrca : and 15 : ld b,a : ld c,4
.loopColumnC3 ld a,(hl) : ld (de),a : expandNextLineDE (void) : ld a,l : add c : ld l,a : djnz .loopColumnC3
ret
;---------------------------------------------------------------------
ScrollDroite
;---------------------------------------------------------------------
ld a,(ix+multi.mapOffset) : and 63 : cp 64-16 : ret z ; gérer le bord droit
ld a,(ix+multi.HSSR) : bit 2,a : jr z,.willDraw : sub 4 : ld (ix+multi.HSSR),a : ret
.willDraw
sub 4 : jr nc,.stillHSSR : jr z,.stillHSSR
ld hl,(ix+multi.crtcHL) : inc hl : ld (ix+multi.crtcHL),hl
ld a,12
.stillHSSR ld (ix+multi.HSSR),a
ld hl,(ix+multi.mapOffset) : ld bc,16 : add hl,bc : ld bc,64 : exx ; HL'=adresse de la tile BC'=saut de ligne dans la tileMap
ld hl,(ix+multi.adresseDebut) : ld bc,64 : ld a,h : and %11111000 : ld d,a : add hl,bc : ld a,h : and 7 : or d ; gère le rebouclage de bloc!
ex hl,de ; DE=haut de la colonne à rafraichir
call afficheColonne
ld a,(ix+multi.colonne) : inc a : and 3 : ld (ix+multi.colonne),a : jr nz,.stillPosx : inc (ix+multi.mapOffset) : .stillPosx
ld hl,(ix+multi.adresseDebut) : inc hl : ld a,h : and 7 : or l : jr nz,.skip : ld a,h : sub 8 : ld h,a : .skip : ld (ix+multi.adresseDebut),hl
ret
;---------------------------------------------------------------------
ScrollBas
;---------------------------------------------------------------------
ld hl,(ix+multi.mapOffset) : ld a,hi(tileMap+48*64) : cp h : ret z ; trop bas, on ne fait rien!
; la tuile en bas sera 16 lignes de tuiles plus bas, soit 1024 octets de tileMap de largeur 64
ld bc,16*64 : add hl,bc : exx ; ajouter 16x64 à l'offset de tuile car on va afficher en bas de l'écran + sauvegarde dans HL'
ld de,(ix+multi.adresseDebut) ; écran carré, calculs simples, le bas revient en haut et vice versa :)
call afficheTuilesHorizontalesDeuxLignes
; mettre à jour les informations courantes
ld a,(ix+multi.ligne) : add 8 : cp 64 : jr nz,.pasDeChangementDeTuile ; ligne contient l'offset de début de la ligne suivante
ld hl,(ix+multi.mapOffset) : ld bc,64 : add hl,bc : ld (ix+multi.mapOffset),hl : xor a ; passer à la tuile dessous
.pasDeChangementDeTuile
ld (ix+multi.ligne),a ; valider la ligne de tuile
ld hl,(ix+multi.adresseDebut) : call NextLineHL : call NextLineHL : ld (ix+multi.adresseDebut),hl
ld a,(ix+multi.VSSR) : add #20 : and #60 : ld (ix+multi.VSSR),a : jr nz,.pasDeChangementDeBloc
ld hl,(ix+multi.crtcHL) : ld bc,32 : add hl,bc : ld (ix+multi.crtcHL),hl ; adresse CRTC augmente de 32 mots si le bloc change
.pasDeChangementDeBloc
ret
;---------------------------------------------------------------------
ScrollHaut
;---------------------------------------------------------------------
ld hl,(ix+multi.mapOffset) : ld a,hi(tileMap) : cp h : jr nz,.okPourLeScroll ; si on est près du début on doit contrôler le "Y"
ld a,l : cp 63 : jr nc,.okPourLeScroll ; si on est sur la première ligne, on doit regarder la ligne de tuile!
ld a,(ix+multi.ligne) : or a : ret z ; tout en haut, aurevoir!
.okPourLeScroll ; on peut scroller!
; mettre à jour les informations courantes
ld a,(ix+multi.ligne) : sub 8 : jr nc,.pasDeChangementDeTuile ; ligne contient l'offset de début de la ligne suivante
ld hl,(ix+multi.mapOffset) : ld bc,-64 : add hl,bc : ld (ix+multi.mapOffset),hl : ld a,64-8 ; passer à la dernière ligne de la tuile dessous
.pasDeChangementDeTuile
ld (ix+multi.ligne),a ; valider la ligne de tuile
ld hl,(ix+multi.adresseDebut) : call PreviousLineHL : call PreviousLineHL : ld (ix+multi.adresseDebut),hl
ld a,(ix+multi.VSSR) : sub #20 : and #60 : ld (ix+multi.VSSR),a : cp #60 : jr nz,.pasDeChangementDeBloc
ld hl,(ix+multi.crtcHL) : ld bc,-32 : add hl,bc : ld (ix+multi.crtcHL),hl ; adresse CRTC baisse de 32 mots si le bloc change
.pasDeChangementDeBloc
; on affiche après en remontant
ld hl,(ix+multi.mapOffset) : exx
ld de,(ix+multi.adresseDebut)
; on continue directement dans l'affichage des lignes
;-------------------------------
afficheTuilesHorizontalesDeuxLignes
;-------------------------------
push de
.Paires
ld a,(ix+multi.colonne) : or a : jp nz,.routineClippee
calculeAdresseTuileLigne 1 : ldi 4 : res 3,d : ld (suiteImpaire.imp0+1),hl ; adresse de la ligne suivante de la tuile à la bonne ligne
.loop
repeat 15,x
calculeAdresseTuileLigne 1 : ldi 4 : res 3,d : ld (suiteImpaire.imp{x}+1),hl ; adresse de la ligne suivante de la tuile à la bonne ligne
rend
jp suiteImpaire.NonClippee
;---------------
.routineClippee
calculeAdresseTuileLigneColonne 1
ld a,4 : sub (ix+multi.colonne) : ld c,a : ld (suiteImpaire.lenFirst+1),a
ld b,0 : ldir : res 3,d
ld a,(ix+multi.colonne) : add l : ld l,a : ld (suiteImpaire.impFirst+1),hl ; adresse de la ligne suivante de la tuile à la bonne colonne
repeat 15,x
calculeAdresseTuileLigne 1 : ldi 4 : res 3,d : ld (suiteImpaire.imp{x}+1),hl ; adresse de la ligne suivante de la tuile à la bonne ligne
rend
calculeAdresseTuileLigne 0
ld c,(ix+multi.colonne)
ld b,0 : ldir : res 3,d
ld a,4 : sub (ix+multi.colonne) : add l : ld l,a : ld (suiteImpaire.impLast+1),hl ; adresse de la ligne suivante de la tuile à la bonne colonne
suiteImpaire
.clippee
pop de : ld a,d : add 8 : ld d,a
.impFirst ld hl,#1234
.lenFirst ld c,#12
ld b,0 : ldir : dec de : res 3,d : inc de : set 3,d
call .loop
.impLast ld hl,#1234
ld c,(ix+multi.colonne)
ld b,0 : ldir
ret
.NonClippee
pop de : ld a,d : add 8 : ld d,a
.imp0 ld hl,#1234 : ldi 3 : ld a,(hl) : ld (de),a : res 3,d : inc de : set 3,d
.loop
repeat 15,x
.imp{x} ld hl,#1234 : ldi 3 : ld a,(hl) : ld (de),a : res 3,d : inc de : set 3,d
rend
ret
;---------------------------------------------------------------------
InitEcran
; IX = structure buffer
; A = poids fort de la page vidéo
ld (ix+multi.nextBuffer),de
ld hl,depx : ld (hl),0
ld hl,depy : ld (hl),0
ld hl,tileMap
ld (ix+multi.mapOffset),hl
ld hl,0
ld (ix+multi.HSSR),h
ld (ix+multi.VSSR),h
ld (ix+multi.colonne),h
ld (ix+multi.ligne),h
ld (ix+multi.crtcHL),hl
ld h,a : ld (ix+multi.adresseDebut),hl
rrca : rrca : ld (ix+multi.crtc12),a
; Afficher les tuiles sur tout l'écran
ld de,(ix+multi.adresseDebut)
ld ix,tileMap ; on n'utilise plus la structure à partir de là
ld yh,16 ; 16 tuiles en hauteur
afficheLigne
ld yl,16 ; nombre de tuiles en largeur
push de ; sauvegarder l'adresse de début de ligne de l'écran
afficheTuile
push de ; sauvegarder l'adresse du début de la tuile à l'écran
ld h,(ix+0) : inc ix : ld l,0 : srl hl : srl hl ; x 256 / 4 c'est la taille de nos tuiles (64 octets)
ld bc,tuiles : add hl,bc ; on a l'adresse de la tile
ld a,16
afficheLigneTuile
push de : ldi 4 : pop de
exa : call NextLineDE : exa
dec a : jr nz,afficheLigneTuile
pop hl : ld bc,4 : add hl,bc : ex hl,de ; se placer juste à côté de la tuile précédente
dec yl : jr nz,afficheTuile
ld bc,48 : add ix,bc ; revenir à la ligne de tuile (64-16 dans notre cas)
pop hl : ld bc,128 : add hl,bc : ex hl,de ; se placer sous les tuiles à gauche
dec yh : jr nz,afficheLigne
ret
;---------------------------------------------------------------------
NextLineHL ld a,h : add 8 : ld h,a : and #38 : ret nz ; tester le changement de bloc sur n'importe quelle page
ld a,64 : add l : ld l,a : ld a,#C0 : adc h : ld h,a : res 3,h : ret
PreviousLineHL ld a,h : sub 8 : ld h,a : and #38 : cp #38 : ret nz ; test du chgt de bloc (bis)
ld a,l : add #C0 : ld l,a : ld a,#3F : adc h : ld h,a : set 3,h : ret
NextLineDE ld a,d : add 8 : ld d,a : and #38 : ret nz ; tester le changement de bloc sur n'importe quelle page
ld a,64 : add e : ld e,a : ld a,#C0 : adc d : ld d,a : res 3,d : ret
;---------------------------------------------------------------------
UpdateHardware
call WaitVBL
RMR2 ASICON
ld a,(ix+multi.HSSR) : or (ix+multi.VSSR) : or #80 : ld (#6804),a
ld hl,(ix+multi.crtcHL) : ld a,h : and 3 : or (ix+multi.crtc12) : ld bc,#BC00+12 : out (c),c : inc b : out (c),a
inc c : dec b : out (c),c : inc b : out (c),l
RMR2 ASICOFF
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
paletteplus: defw #323,#646,#5B3,#967,#A57,#B95,#6E4,#9B7,#C89,#ABA,#CE2,#DB8,#DB9,#EC6,#EC9,#EED
align 256 : tuiles incbin 'mapMulti.bin'
align 256 : tileMap include 'mapMulti.tilemap'
; et on se déclare deux structures pour un double buffer
struct multi ecran1
struct multi ecran2
depx defb 0
depy defb 0
|