Optimisation de nos macros de split-screen
De façon évidente, nos macros n'utilisent pas tous les registres secondaires, le registre BC est inutilisé.
On va s'en servir pour recharger H en fin de routine et faire un AND registre plutôt que valeur immédiate. 2 nops gagnés!
On ajoute le pré-chargement de BC à notre interruption 255. ld bc,(hi(SPLIT_TABLE)<<8)|#70 ; valeurs utilisées à chaque INT en cache registre
Une autre optimisation serait de limiter les écritures pour le changement du vecteur d'interruption courant.
Si on organise les adresses de nos routines d'interruption de sorte qu'on ne change que soit le poids fort, soit le poids faible, on gagne encore des nops!
L'idée serait de faire l'aller sur un poids fort et le retour sur le poids fort suivant. Puis recommencer. #1000
#1040 ; changement du poids faible pour l'aller
#1080 ; idem
#10C0 ; idem
#11C0 ; changement du poids fort, faire le retour
#1180 ; poids faible
#1140 ; poids faible
#1100 ; poids faible
#1200 ; changement de poids fort, nouvel aller
...
On va se préparer un lot d'adresses qui respecte notre contrainte
routineAdresse=AXELAY_ROUTINES
routineIndex=0
repeat 10
routineAdresse{routineIndex}=routineAdresse : routineIndex+=1 : routineAdresse+=64
routineAdresse{routineIndex}=routineAdresse : routineIndex+=1 : routineAdresse+=64
routineAdresse{routineIndex}=routineAdresse : routineIndex+=1 : routineAdresse+=64
routineAdresse{routineIndex}=routineAdresse : routineIndex+=1 : routineAdresse+=#100
routineAdresse{routineIndex}=routineAdresse : routineIndex+=1 : routineAdresse-=64
routineAdresse{routineIndex}=routineAdresse : routineIndex+=1 : routineAdresse-=64
routineAdresse{routineIndex}=routineAdresse : routineIndex+=1 : routineAdresse-=64
routineAdresse{routineIndex}=routineAdresse : routineIndex+=1 : routineAdresse+=#100
rend
Et on va se créer une macro qui change soit le poids faible, soit le poids fort, en fonction de l'adresse précédente. Encore quelques nops de gagné.
macro prochaineAdresse
ancienneAdresse=routineAdresse{routineIndex} : routineIndex+=1
if lo(ancienneAdresse!=lo(routineAdresse{routineIndex}) : ld a,lo(routineAdresse{routineIndex}) : ld (#39),a : else : ld a,hi(routineAdresse{routineIndex}) : ld (#3A),a : endif
mend
Reste une belle optimisation à 4 nops qui consisterait à ne pas reprogrammer le PRI mais utiliser une liste d'interruptions DMA. On se la garde sous le coude pour le moment.
Voici en visuel le gain obtenu, on visualise de suite que le temps occupé par l'interruption est moins long.

On ajoute des rasters sur l'horizon?
On va ajouter du brouillard au fond pour renforcer la perspective. Histoire de ne pas trop se prendre la tête au doigt mouillé, nous écrivons un petit programme qui prend notre palette et calcule les couleurs de transition du brouillard (ici #999) vers la couleur destination.
macro grade,compo,force
col=int((9*{force}+(6-{force})*{compo})/6)
col=clamp(col,0,15)
mend
macro gradecol,couleur,force
r={couleur}>>8
v=({couleur}>>4)&0xf
b={couleur}&0xf
grade r,{force} : r=col
grade v,{force} : v=col
grade b,{force} : b=col
col{cindex}=((r<<8)|(v<<4)|b)
cindex+=1
mend
repeat 7,force,0
cindex=0
gradecol #010,force
gradecol #040,force
gradecol #060,force
gradecol #090,force
gradecol #291,force
gradecol #0B0,force
gradecol #1C1,force
gradecol #0D0,force
gradecol #3D2,force
gradecol #1E1,force
gradecol #3F1,force
gradecol #4F2,force
gradecol #6F3,force
gradecol #9F3,force
gradecol #CF4,force
gradecol #FF7,force
print 'defw ',{hex}col0,',',{hex}col1,',',{hex}col2,',',{hex}col3,',',{hex}col4,',',{hex}col5,',',{hex}col6,',',{hex}col7,',',{hex}col8,',',{hex}col9,',',{hex}col10,',',{hex}col11,',',{hex}col12,',',{hex}col13,',',{hex}col14,',',{hex}col15
rend
L'exécution de notre programme va nous sortir 7 palettes, de la référence au brouillard complet
Pre-processing [makeGradiant.asm]
Assembling
defw #10 , #40 , #60 , #90 , #0291 , #B0 , #01C1 , #D0 , #03D2 , #01E1 , #03F1 , #04F2 , #06F3 , #09F3 , #0CF4 , #0FF7
defw #0222 , #0252 , #0272 , #0292 , #0392 , #02B2 , #02C2 , #02C2 , #04C3 , #02D2 , #04E2 , #05E3 , #07E4 , #09E4 , #0CE5 , #0EE7
defw #0343 , #0363 , #0373 , #0393 , #0494 , #03A3 , #04B4 , #03C3 , #05C4 , #04C4 , #05D4 , #06D4 , #07D5 , #09D5 , #0BD6 , #0DD8
defw #0555 , #0575 , #0585 , #0595 , #0695 , #05A5 , #05B5 , #05B5 , #06B6 , #05C5 , #06C5 , #07C6 , #08C6 , #09C6 , #0BC7 , #0CC8
defw #0666 , #0676 , #0686 , #0696 , #0796 , #06A6 , #06A6 , #06A6 , #07A7 , #06B6 , #07B6 , #07B7 , #08B7 , #09B7 , #0AB7 , #0BB8
defw #0888 , #0888 , #0898 , #0898 , #0898 , #0898 , #08A8 , #08A8 , #08A8 , #08A8 , #08A8 , #08A8 , #09A8 , #09A8 , #0AA8 , #0AA9
defw #0999 , #0999 , #0999 , #0999 , #0999 , #0999 , #0999 , #0999 , #0999 , #0999 , #0999 , #0999 , #0999 , #0999 , #0999 , #0999
Warning: Not a single byte to output
Pour rappel, notre rouleau ne fait jamais de split deux lignes de suite, il est moins prononcé que celui d'Axelay pour cette raison mais cela nous dégage du temps libre pour changer les couleurs de la palette. Nous avons un peu moins de 75 nops de disponible entre deux interruptions. Mettons 70.
Si on s'insère avant le retour d'interruption, on évitera un changement de contexte, le saut vers la routine et le retour de la routine.
On va dupliquer la macro Skip pour en faire une version qui n'écrit pas le code de retour. Et se faire une macro pour le code retour.
macro splitEnd
exx : exa ; re-permuter avant de rendre la main
ei : ret
mend
Ensuite commence le travail de fourmi pour écrire la palette.
defw #0666,#0676,#0686,#0696,#0796,#06A6,#06A6,#06A6,#07A7,#06B6,#07B6,#07B7,#08B7,#09B7,#0AB7,#0BB8Commençons par écrire du code naif avec nos registres de travail disponibles, A et DE.
ld de,#0666 : ld (#6400),de
ld de,#0676 : ld (#6402),de
ld de,#0686 : ld (#6404),de
ld de,#0696 : ld (#6406),de
ld de,#0796 : ld (#6408),de
ld de,#06A6 : ld (#640a),de
ld de,#06A6 : ld (#640c),de
ld de,#06A6 : ld (#640e),de
ld de,#07A7 : ld (#6410),de
ld de,#06B6 : ld (#6412),de
ld de,#07B6 : ld (#6414),de
ld de,#07B7 : ld (#6416),de
ld de,#08B7 : ld (#6418),de
ld de,#09B7 : ld (#641a),de
ld de,#0AB7 : ld (#641c),de
ld de,#0BB8 : ld (#641e),de
C'est gros, +100 octets (premier problème) et c'est lent, +150 nops (deuxième problème) mais on voit qu'il va facilement s'optimiser et qu'il semble possible de le découper en deux parties et de factoriser un peu les affectations.
ld de,#06A6 : ld (#640a),de
ld de,#06A6 : ld (#640c),de
ld de,#06A6 : ld (#640e),de
ld e,#66 : ld (#6400),de
ld e,#76 : ld (#6402),de
ld e,#86 : ld (#6404),de
ld e,#96 : ld (#6406),de
inc d : ld (#6408),de
ld de,#07A7 : ld (#6410),de
ld de,#06B6 : ld (#6412),de
inc d : ld (#6414),de
inc e : ld (#6416),de
inc d : ld (#6418),de
inc d : ld (#641a),de
inc d : ld (#641c),de
inc d : inc e : ld (#641e),de
À priori ça va rentrer au chausse-pied. Dans le cas où il n'est pas possible d'optimiser les changements de palette, il faudra découper en 3.
Finalement, on modifie notre macro qui calcule les gradients pour écrire directement le code naif.
macro grade,compo,force
col=int((9*{force}+(6-{force})*{compo})/6)
col=clamp(col,0,15)
mend
macro gradecol,couleur,force
r={couleur}>>8
v=({couleur}>>4)&0xf
b={couleur}&0xf
grade r,{force} : r=col
grade v,{force} : v=col
grade b,{force} : b=col
col{cindex}=((r<<8)|(v<<4)|b)
cindex+=1
mend
repeat 7,force,0
cindex=0
gradecol #010,force : gradecol #040,force
gradecol #060,force : gradecol #090,force
gradecol #291,force : gradecol #0B0,force
gradecol #1C1,force : gradecol #0D0,force
gradecol #3D2,force : gradecol #1E1,force
gradecol #3F1,force : gradecol #4F2,force
gradecol #6F3,force : gradecol #9F3,force
gradecol #CF4,force : gradecol #FF7,force
repeat 16,xx,0
print 'ld de,',{hex}col{xx},' : ld (',{hex}(#6400+xx*2),'),de ; ',{hex}col{xx}
rend
print '===================='
rend
On modifie notre interruption 255 pour appeler une nouvelle interruption avant nos routines de split. On change la ligne et le vecteur de la prochaine interruption à appeler, on va se placer quelques lignes avant les splits.
ld a,17 : ld (#6800),a ; PRI
ld hl,interruptionCiel : ld (#39),hl ; first rupture INT
Et notre nouvelle interruption va afficher la palette la plus proche du brouillard, avec une exception pour la couleur du ciel qui reste bleutée.
interruptionCiel
exx : exa : ld de,#55C : ld (#6400),de ; changer le ciel au plus vite
push hl
ld hl,depuisBrouillard : ld de,#6402 : ldi 30
ld a,21 : ld (#6800),a ; PRI
ld hl,AXELAY_ROUTINES : ld (#39),hl ; first rupture INT
ld bc,(hi(SPLIT_TABLE)<<8)|#70 ; valeurs utilisées à chaque INT en cache registre
pop hl
exx : exa
ei : ret
depuisBrouillard defw #0888,#0898,#0898,#0898,#0898,#08A8,#08A8,#08A8,#08A8,#08A8,#08A8,#09A8,#09A8,#0AA8,#0AA9 ; moins la couleur zéro
Allez, on fait une passe sur le source précédent pour ajouter les rasters partout, voici les changements au niveau des split-screens. Et si vous voulez télécharger le paquet compilable, il est [ICI].
 Roudoudou CPCrulez[Content Management System] v8.732-desktop/c Page créée en 184 millisecondes et consultée 22 foisL'Amstrad CPC est une machine 8 bits à base d'un Z80 à 4MHz. Le premier de la gamme fut le CPC 464 en 1984, équipé d'un lecteur de cassettes intégré il se plaçait en concurrent du Commodore C64 beaucoup plus compliqué à utiliser et plus cher. Ce fut un réel succès et sorti cette même années le CPC 664 équipé d'un lecteur de disquettes trois pouces intégré. Sa vie fut de courte durée puisqu'en 1985 il fut remplacé par le CPC 6128 qui était plus compact, plus soigné et surtout qui avait 128Ko de RAM au lieu de 64Ko. |
|