AXELAY_ROUTINES equ #1000
SPLIT_TABLE equ #3D00 ; table sur la zone #3D00-#3FFF
include 'system.asm' ; RMR/RMR2/UnlockAsic
buildsna
bankset 0
org #100 : run #100
ld sp,#100
RMR ROM_OFF|MODE_0
UnlockAsic (void) ; macro de delock de l'ASIC (system.asm)
RMR2 ASICON ; activer la page de l'ASIC
call preComputeASICinfo
ld bc,#BC01 : out (c),c : ld bc,#BD20 : out (c),c ; 32 word width
ld bc,#BC02 : out (c),c : ld bc,#BD00+43 : out (c),c ; centrer à l'horizontale
ld bc,#BC06 : out (c),c : ld bc,#BD20 : out (c),c ; 32 block height
ld bc,#BC07 : out (c),c : ld bc,#BD22 : out (c),c ; centrer à la verticale
ld bc,#BC00+12 : out (c),c : ld bc,#BD20 : out (c),c ; début de l'écran visible en #8000-#BFFF
ld bc,#BC00+13 : out (c),c : ld bc,#BD00 : out (c),c ; poids faible de l'adresse de départ vidéo
ld a,255 : ld (#6800),a ; toute première interruption ligne 255
ld hl,interrupt255 : ld (#39),hl ; vecteur de l'int255
ld a,#C3 : ld (#38),a ; opcode du JP qu'on met en #38
; on attend la VBL pour activer notre palette et lancer les interruptions
; ce n'est PAS grave si l'interruption 255 est exécutée pendant la VBL
; car une interruption était en attente. Tout va bien se passer :)
firstVBL ld b,#F5 : in a,(c) : rra : jr nc,firstVBL
ld hl,lavaPAL : ld de,#6400 : ld bc,32 : ldir
ei
;=============================================
reloop
;=============================================
nop : nop : inc hl : ld a,0 : trigger=$-1 : or a : jr z,reloop : xor a : ld (trigger),a
; la valeur de HL avant de le remettre à zéro nous donnera le temps disponible réel à multiplier par 10
ld hl,0
jr reloop
lavaPAL defw #010,#040,#060,#090,#291,#0B0,#1C1,#0D0,#3D2,#1E1,#3F1,#4F2,#6F3,#9F3,#CF4,#FF7
interrupt255
exx : exa
ld a,21 : ld (#6801),a ; SPLT
ld a,21 : ld (#6800),a ; PRI
ld hl,AXELAY_ROUTINES : ld (#39),hl ; first rupture INT
; interrupt registers reset
.offset ld hl,SPLIT_TABLE+1 ; start a little further to avoid refresh data
.offsetPhase ld a,0 : inc a : and 1 : ld (.offsetPhase+1),a : jr nz,.offsetSkip
dec l
ld (.offset+1),hl
.offsetSkip
inc h : ld d,(hl) : inc h : ld e,(hl) : dec h : dec h : ld (#6802),de ; SPLIT ADDR
xor a : ld (#6804),a ; SSR reset pour le haut de l'écran
inc a : ld (trigger),a ; TRIGGER est une variable remise à 1 une fois par frame
exx : exa
ei : ret
preComputeASICinfo
; produire le tableau des adresses prémâchées CRTC/ASIC pour chacune des 256 lignes d'un écran carré de 64 de large
; SSR Block
; CRTC-13
; CRTC-12
ld ix,SPLIT_TABLE ; adresse de nos 3 tables, alignée sur 256 octets
ld hl,#C000 ; adresse de départ de nos données à afficher
ld c,32 ; nous avons 32 blocs de haut (de 8 lignes)
.computeASIClines
ld b,8 ; boucler sur les 8 lignes d'un bloc
.computeASIClinesBlock
push hl
ld a,h
add a
and #70
ld (ix+0),a ; valeur de bloc prémâchée pour le SSR
inc xh
srl h : rr l
ld a,l
ld (ix+0),a ; poids faible de l'adresse CRTC (REG13)
inc xh
; le calcul ci-dessous est compatible avec n'importe quelle adresse mémoire
; on découpe l'adresse pour renseigner les bits 0,1, 4 et 5 de l'équivalent CRTC registre 12
ld l,h
ld a,h
and #3
ld h,a
ld a,l
srl a
and #30
or h
ld (ix+0),a ; équivalent du REG12
ld xh,hi(SPLIT_TABLE) ; revenir sur le poids fort de départ de nos tables
inc xl ; passer à la ligne suivante dans les tables
pop hl
ld de,#800 ; aller à la ligne du dessous dans le bloc
add hl,de
djnz .computeASIClinesBlock
ld de,64-#4000 ; aller à la ligne du dessous en changeant de bloc
add hl,de
dec c ; encore un bloc à traiter?
jr nz,.computeASIClines
ret
; on va commencer à générer des routines à l'adresse qu'on a choisie (ici #1000)
routineAdresse=AXELAY_ROUTINES
; nos routines font un peu plus de quarante octets, il est facile de connaitre l'adresse
; de la suivante
compensation=#20
splitLine=21
macro splitSkip,combien
org routineAdresse : routineAdresse+=64
exx : exa ; permuter les registres AF,BC,DE,HL
ld a,compensation ; compensation de bloc en accord avec la ligne
compensation=compensation-#10*{combien} ; on ajoute autant de compensation qu'on avance
while compensation<0 : compensation+=#80 : wend ; cette boucle corrige la valeur pour qu'elle soit toujours entre #00 et #70
add (hl) : and #70 : ld (#6804),a ; ajouter au bloc de la ligne voulue, capper, mettre dans le SSR
ld a,l : add {combien}+1 : ld l,a ; sauter 1 ligne rapport à la ligne courante et avancer dans notre tableau de définition des lignes
inc h : ld d,(hl) : inc h : ld e,(hl) : ld (#6802),de ; prochaine adresse de rupture programmée
splitLine+={combien} ; mettre à jour notre variable qui tient le compte des lignes
ld a,splitLine : ld (#6801),a : ld (#6800),a ; prochaine INT et rupture à la même ligne
ld de,routineAdresse : ld (#39),de ; changer le vecteur pour la prochaine INT
ld h,hi(SPLIT_TABLE) ; adresse de table prête pour la prochaine INT
exx : exa ; re-permuter avant de rendre la main
ei : ret
mend
macro splitDuplicate,combien
org routineAdresse : routineAdresse+=64
exx : exa ; permuter les registres AF,BC,DE,HL
ld a,compensation ; compensation de bloc en accord avec la ligne
compensation=compensation-#10*{combien} ; on ajoute autant de compensation qu'on avance
while compensation<0 : compensation+=#80 : wend ; cette boucle corrige la valeur pour qu'elle soit toujours entre #00 et #70
add (hl) : and #70 : ld (#6804),a ; ajouter au bloc de la ligne voulue, capper, mettre dans le SSR
if {combien}
ld a,l : add {combien}-1 : ld l,a ; revenir 1 ligne rapport à la ligne courante et reculer dans notre tableau de définition des lignes
inc h : ld d,(hl) : inc h : ld e,(hl) : ld (#6802),de ; prochaine adresse de rupture programmée
splitLine+={combien} ; mettre à jour notre variable qui tient le compte des lignes
assert splitLine<254,'trop loin dans les interruptions!',splitLine
ld a,splitLine : ld (#6801),a : ld (#6800),a ; prochaine INT et rupture à la même ligne
ld de,routineAdresse : ld (#39),de ; changer le vecteur pour la prochaine INT
ld h,hi(SPLIT_TABLE) ; adresse de table prête pour la prochaine INT
else
; dernière ligne, plus de split
ld a,255 : ld (#6800),a
ld hl,interrupt255 : ld (#39),hl
endif
exx : exa ; re-permuter avant de rendre la main
ei : ret
mend
; Et voici un rouleau, plus doux qu'un rouleau de démo ou celui d'Axelay, on veut
; garder du temps machine disponible...
splitSkip 2
splitSkip 2
splitSkip 2
splitSkip 2
splitSkip 2
splitSkip 2
splitSkip 2
splitSkip 3
splitSkip 3
splitSkip 3
splitSkip 3
splitSkip 3
splitSkip 4
splitSkip 4
splitSkip 4
splitSkip 4
splitSkip 5
splitSkip 5
splitSkip 5
splitSkip 6
splitSkip 6
splitSkip 7
splitSkip 9
splitSkip 10
splitSkip 13
splitSkip 36
splitDuplicate 13
splitDuplicate 10
splitDuplicate 9
splitDuplicate 7
splitDuplicate 6
splitDuplicate 5
splitDuplicate 5
splitDuplicate 4
splitDuplicate 4
splitDuplicate 4
splitDuplicate 3
splitDuplicate 3
splitDuplicate 3
splitDuplicate 3
splitDuplicate 2
splitDuplicate 2
splitDuplicate 2
; la dernière n'a pas de rupture qui suit!
; grâce au zéro en paramètre, on sait qu'on doit terminer
; On se contente de positionner le SSR et arrêter la tambouille
splitDuplicate 0
; Enfin, notre texture qui ne bouge pas dans la mémoire vidéo
org #C000
incbin 'lavaFire.bin'
|