;Un usage avancé du Copper : MOVE, WAIT, SKIP et JUMP pour afficher une zone dessinée par un nombre quelconque de MOVE (enfin, entre 1 et 40) dont l'ordonnée et la hauteur sont quelconques. Sans doute le truc le plus chiant que j'ai jamais codé... ;ATTENTION ! ASM-One 1.20 interprète IF X<100 comme <= 100, mais il interprète IF X>100 comme > 100 ! Mais c'est sans doute que IF ne s'utilise jamais sans condition (syntaxe IF(cc), comme indiqué dans le guide...). A ce propos, noter qu'un IFNE [condition] est validé si jamais la condition est vraie, car l'évaluation de la condition donne VRAI qui vaut 1 et non FAUX qui vaut 0... Pas des plus intuitif. ;Par Denis Duplan (denis.duplan@gmail.com) pour Stash of Code (http:://www.stashofcode.fr) en août 2017 ;Cette oeuvre est mise à disposition selon les termes de la Licence Creative Commons Attribution – Pas d’Utilisation Commerciale – Partage dans les Mêmes Conditions 4.0 France. ;---------- Directives ---------- SECTION yragael,CODE_C ;---------- Constantes ---------- ;Registres FMODE=$1FC INTENA=$09A INTENAR=$01C INTREQ=$09C INTREQR=$01E DMACON=$096 DMACONR=$002 COLOR00=$180 COLOR01=$182 COP1LCH=$080 COP1LCL=$082 COPJMP1=$088 COP2LCH=$084 COP2LCL=$086 COPJMP2=$08A DIWSTRT=$08E DIWSTOP=$090 BPLCON0=$100 BPLCON1=$102 BPLCON2=$104 DDFSTRT=$092 DDFSTOP=$094 BPL1MOD=$108 BPL2MOD=$10A BPL1PTH=$0E0 BPL1PTL=$0E2 ;Programme DISPLAY_DX=320 DISPLAY_DY=256 DISPLAY_X=$81 DISPLAY_Y=$2C DISPLAY_DEPTH=1 COPPERLIST=2000 START=100 ;Correspond à la ligne START-DISPLAY_Y dans le bitplane (START=0 => ligne 44, START=127 => ligne 83, START=255 => ligne 211) END=280 ;Correspond à la ligne END-DISPLAY_Y dans le bitplane (idem) NB_MOVES=40 ;---------- Initialisations ---------- ;Empiler les registres movem.l d0-d7/a0-a6,-(sp) lea $DFF000,a5 ;Allouer de la mémoire en CHIP mise à 0 pour la Copper list move.l #COPPERLIST,d0 move.l #$10002,d1 movea.l $4,a6 jsr -198(a6) move.l d0,copperList ;Allouer de la mémoire en CHIP mise à 0 pour le bitplane (un bitplane 320x256) move.l #DISPLAY_DY*(DISPLAY_DX>>3),d0 move.l #$10002,d1 movea.l $4,a6 jsr -198(a6) move.l d0,bitplane ;Couper le système movea.l $4,a6 jsr -132(a6) ;Couper le matériel comme un gros sale move.w INTENAR(a5),intena move.w #$7FFF,INTENA(a5) move.w INTREQR(a5),intreq move.w #$7FFF,INTREQ(a5) move.w DMACONR(a5),dmacon move.w #$07FF,DMACON(a5) ;---------- Copper list ---------- movea.l copperList,a0 ;Configuration de l'écran move.w #DIWSTRT,(a0)+ move.w #(DISPLAY_Y<<8)!DISPLAY_X,(a0)+ move.w #DIWSTOP,(a0)+ move.w #((DISPLAY_Y+DISPLAY_DY-256)<<8)!(DISPLAY_X+DISPLAY_DX-256),(a0)+ move.w #BPLCON0,(a0)+ move.w #(DISPLAY_DEPTH<<12)!$0200,(a0)+ move.w #BPLCON1,(a0)+ move.w #$0000,(a0)+ move.w #BPLCON2,(a0)+ move.w #$0000,(a0)+ move.w #DDFSTRT,(a0)+ move.w #((DISPLAY_X-17)>>1)&$00FC,(a0)+ move.w #DDFSTOP,(a0)+ move.w #((DISPLAY_X-17+(((DISPLAY_DX>>4)-1)<<4))>>1)&$00FC,(a0)+ move.w #BPL1MOD,(a0)+ move.w #(DISPLAY_DEPTH-1)*(DISPLAY_DX>>3),(a0)+ move.w #BPL2MOD,(a0)+ move.w #(DISPLAY_DEPTH-1)*(DISPLAY_DX>>3),(a0)+ ;Comptabilité OCS avec AGA move.w #FMODE,(a0)+ move.w #$0000,(a0)+ ;Adresse du bitplane move.w #BPL1PTL,(a0)+ move.l bitplane,d0 move.w d0,(a0)+ move.w #BPL1PTH,(a0)+ swap d0 move.w d0,(a0)+ ;Palette move.w #COLOR01,(a0)+ move.w #$0FFF,(a0)+ ;Couleur de fond à noir move.w #COLOR00,(a0)+ move.w #$0000,(a0)+ ;Test d'une boucle : répéter une série de NB_MOVES MOVE à partir du début du bitplane (position horizontale $3E) entre les lignes START et END incluses ;Il est impossible de demander au Copper d'attendre le faisceau d'électrons sur une position horizontale uniquement, du moins sur l'intégralité des positions verticales possibles. En effet, s'il est bien possible de spécifier un masque à appliquer à la position verticale pour limiter sa comparaison aux bits non masqués de la valeur Y sur 8 bits spécifiée dans l'octet de poids fort du second mot, il est impossible de masquer le bit 7. Or à partir de la position verticale $80 (ie : 128), le bit 7 de la position verticale passe à 1. Ce bit est comparé à Y, où il est à 0. La position verticale courante étant donc supérieure à Y, le WAIT est validé, quelle que soit le résultat de la comparaison sur la position horizontale. La série de MOVE est donc exécutée avant la position horizontale où le faisceau d'électrons était attendu. C'est le problème décrit dans l'Amiga Hardware Reference Manual pour l'instruction SKIP, rencontré ici pour l'instruction WAIT dans une boucle où la numéro de la ligne est conduit à passer $80 (à quoi s'ajoute un autre problème, celui de passer $100). ;SYNTHESE GENERALE ; ;// hp est une valeur paire dans [$00, $E0] en PAL ;// vp est une valeur quelconque dans [$00, $FF] ;// he est une valeur quelconque dans [$00, $7F] (son bit 7 sera toujours mis à 1) ;// ve est une valeur paire dans [$00, $FE] ; ;typedef unsigned char BYTE; ; ;function WAIT (BYTE hp, BYTE he, BYTE he, BYTE ve) { ; ve = $80 | ve; // Le bit 7 de y et vp ne peut être masqué ; if ((y & ve) >= (vp & ve)) ; return; ; while ((y & ve) < (vp & ve)); ; while ((x & he) < (hp & he)); ;} ; ;function SKIP (BYTE hp, BYTE vp, BYTE he, BYTE ve) { ; ve = $80 | ve; // Le bit 7 de y et vp ne peut être masqué ; if ((y & ve) >= (vp & ve)) { ; if ((x & he) >= (hp & he)) ; return (true); ; } ; return (false); ;} ; ;L'algorithme est le suivant, x et y correspondant aux coordonnées du faisceau d'électrons qui évoluent parallèlement sur 8 bits (donc rebouclant par overflow à chaque trame) comme dans un autre thread, et SKIP () et WAIT () comparant x et y aux valeurs fournies après application des masques fournis à x et y ainsi qu'à ces valeurs : ; ;Il faut donc noter que SKIP (x, y, mx, my) est équivalent à SKIP (x, y, mx, my ! $80), et de même pour WAIT (). ; ;if (START > 255) ; WAIT ($E0, $FF, $FE, $7F) // Attendre d'être en ($E0, $FF) ou au-delà ;if (START < 255) { ; WAIT ($00, START, $FE, $7F) // Attendre d'être en ($00, START) ou au-delà ; while (true) { ; if (SKIP ($00, $80, $00, $00)) { // Tester si on est en (%xxxxxxxx, $80) ou au-delà ; WAIT ($3E, $80, $FE, $00) // Attendre d'être en ($3E, %1xxxxxxx) ou au-delà ; for (i = 0 i != NB_MOVES i ++) ; move (value, COLOR00) ; if (NB_MOVES <= 38) ; WAIT ($E0, $80, $FE, $00) // Attendre d'être en ($E0, %1xxxxxxx) ou au-delà ; } ; else { ; WAIT ($3E, $00, $FE, $00) // Attendre d'être en ($3E, %0xxxxxxx) ou au-delà ; for (i = 0 i != NB_MOVES i ++) ; move (value, COLOR00) ; if (NB_MOVES <= 38) ; WAIT ($E0, $00, $FE, $00) // Attendre d'être en ($E0, %0xxxxxxx) ou au-delà ; } ; if ((END >= 255) && (START <= 255)) { ; if (SKIP ($00, $FF, $00, $7F) { // Tester si on est en (%xxxxxxxx, $FF) ou au-delà ; WAIT ($3E, $FF, $FE, $7F) // Attendre d'être en ($3E, $FF) ou au-delà ; for (i = 0 i != NB_MOVES i ++) ; move (value, COLOR00) ; if (END == 255) ; return ; if (NB_MOVES <= 38) ; WAIT ($E0, $FF, $FE, $7F) // Attendre d'être en ($E0, $FF) ou au-delà ; while (true) { ; WAIT ($3E, $00, $FE, $00) // Attendre d'être en ($3E, %0xxxxxxx) ou au-delà ; for (i = 0 i != NB_MOVES i ++) ; move (value, COLOR00) ; if (NB_MOVES <= 38) ; WAIT ($E0, $00, $FE, $00) // Attendre d'être en ($E0, %0xxxxxxx) ou au-delà ; if (SKIP ($00, (END + 1) & $FF, $00, $7F)) // Tester si on est en (%xxxxxxxx, (END + 1) & $FF) ou au-delà ; return ; } ; } ; } ; if (SKIP ($00, (END + 1) & $FF, $00, $7F)) // Tester si on est en (%xxxxxxxx, (END + 1) & $FF) ou au-delà ; return ; } ;} ;else ; WAIT ($00, $FF, $FE, $7F) // Attendre d'être en ($00, $FF) ou au-delà ;if ((END >= 255) && (START >= 255)) { ; if (SKIP ($00, $FF, $00, $7F) { // Tester si on est en (%xxxxxxxx, $FF) ou au-delà ; WAIT ($3E, $FF, $FE, $7F) // Attendre d'être en ($3E, $FF) ou au-delà ; for (i = 0 i != NB_MOVES i ++) ; move (value, COLOR00) ; if (END == 255) ; return ; if (NB_MOVES <= 38) ; WAIT ($E0, $FF, $FE, $7F) // Attendre d'être en ($E0, $FF) ou au-delà ; while (true) { ; WAIT ($3E, $00, $FE, $00) // Attendre d'être en ($3E, %0xxxxxxx) ou au-delà ; for (i = 0 i != NB_MOVES i ++) ; move (value, COLOR00) ; if (NB_MOVES <= 38) ; WAIT ($E0, $00, $FE, $00) // Attendre d'être en ($E0, %0xxxxxxx) ou au-delà ; if (SKIP ($00, (END + 1) & $FF, $00, $7F)) // Tester si on est en (%xxxxxxxx, (END + 1) & $FF) ou au-delà ; return ; } ; } ;} IF START>255 ;---------- Début de la partie conditionnelle pour le cas START > 255 : Pas de franchissement de $FF ---------- ;Si la position verticale START est > 255, attendre la fin de la ligne 255... move.w #($FF<<8)!$E0!$0001,(a0)+ ;WAIT 1st word (y ! x ! 1) move.w #$8000!($7F<<8)!$00FE!$0000,(a0)+ ;WAIT 2nd word (BFD ! mask y ! mask x ! 0) ;---------- Fin de la partie conditionnelle pour le cas START > 255 : Pas de franchissement de $FF ---------- ENDC IF 255>START ;---------- Début de la partie conditionnelle pour le cas START < 255 : Franchissement potentiel de $FF ---------- ;Préparer l'adresse pour sauter en (A) move.l a0,d0 addi.l #5*4,d0 move.w #COP1LCL,(a0)+ move.w d0,(a0)+ ;MOVE (COP1LCL) swap d0 move.w #COP1LCH,(a0)+ move.w d0,(a0)+ ;MOVE (COP1LCH) ;Attendre la position verticale START et la position horizontale $00 (pour être bien certain de pouvoir attendre la position horizontale à laquelle exécuter les MOVE) move.w #(START<<8)!$00!$0001,(a0)+ ;WAIT 1st word (y ! x ! 1) move.w #$8000!($7F<<8)!$FE!$0000,(a0)+ ;WAIT 2nd word (BFD ! mask y ! mask x ! 0) ;Préparer l'adresse pour sauter en (B) move.l a0,d0 IF 38>NB_MOVES ;Car bogue dans ASM-One 1.20 : < est interprété comme <= ! addi.l #(5+NB_MOVES+4)*4,d0 ELSE addi.l #(5+NB_MOVES+3)*4,d0 ENDC move.w #COP2LCL,(a0)+ move.w d0,(a0)+ ;MOVE (COP2LCL) swap d0 move.w #COP2LCH,(a0)+ move.w d0,(a0)+ ;MOVE (COP2LCH) ;(A) Si la position verticale est < $80, sauter en (B) move.w #($80<<8)!$00!$0001,(a0)+ ;SKIP 1st word (y ! x ! 1) move.w #$8000!($00<<8)!$00!$0001,(a0)+ ;SKIP 2nd word (BFD ! mask y ! mask x ! 1) move.l a0,d0 move.w #COPJMP2,(a0)+ move.w #$0000,(a0)+ ;MOVE (COPJMP2) ;La position verticale est >= $80. Attendre la position horizontale $3E à une position verticale quelconque mais >= $80 (ie : 1xxxxxxx) move.w #($80<<8)!$3E!$0001,(a0)+ ;WAIT 1st word (y ! x ! 1) move.w #$8000!($00<<8)!$FE!$0000,(a0)+ ;WAIT 2nd word (BFD ! mask y ! mask x ! 0) ;Exécuter les MOVE lea colors,a1 REPT NB_MOVES move.w #COLOR00,(a0)+ move.w (a1)+,(a0)+ ;#NB_MOVES MOVE (COLOR00) ENDR ;Attendre la fin de la ligne à la position horizontale $E0 à une position verticale quelconque mais >= 80 (ie : 1xxxxxxx), donc la ligne suivante... IF 38>NB_MOVES ;Car bogue dans ASM-One 1.20 : < est interprété comme <= ! move.w #($80<<8)!$E0!$0001,(a0)+ ;WAIT 1st word (y ! x ! 1) move.w #$8000!($00<<8)!$FE!$0000,(a0)+ ;WAIT 2nd word (BFD ! mask y ! mask x ! 0) ENDC ;Sauter en (C) move.l a0,d0 IF 38>NB_MOVES ;Car bogue dans ASM-One 1.20 : < est interprété comme <= ! addi.l #(4+NB_MOVES+1)*4,d0 ELSE addi.l #(4+NB_MOVES)*4,d0 ENDC move.w #COP2LCL,(a0)+ move.w d0,(a0)+ ;MOVE (COP2LCL) swap d0 move.w #COP2LCH,(a0)+ move.w d0,(a0)+ ;MOVE (COP2LCH) move.w #COPJMP2,(a0)+ move.w #$0000,(a0)+ ;MOVE (COPJMP2) ;(B) La position verticale est < $80. Attendre la position horizontale $3E à une position verticale quelconque mais < $80 (ie : 0xxxxxxx) move.w #($00<<8)!$3E!$0001,(a0)+ ;WAIT 1st word (y ! x ! 1) move.w #$8000!($00<<8)!$FE!$0000,(a0)+ ;WAIT 2nd word (BFD ! mask y ! mask x ! 0) ;Exécuter les MOVE lea colors,a1 lea 40*2(a1),a1 REPT NB_MOVES move.w #COLOR00,(a0)+ move.w -(a1),(a0)+ ;#NB_MOVES MOVE (COLOR00) ENDR ;Attendre la fin de la ligne à la position horizontale $E0 à une position verticale quelconque mais < $80 (ie : 0xxxxxxx), donc la ligne suivante IF 38>NB_MOVES ;Car bogue dans ASM-One 1.20 : < est interprété comme <= ! move.w #($00<<8)!$E0!$0001,(a0)+ ;WAIT 1st word (y ! x ! 1) move.w #$8000!($00<<8)!$FE!$0000,(a0)+ ;WAIT 2nd word (BFD ! mask y ! mask x ! 0) ENDC ;---------- Début de la partie conditionnelle pour le cas START < 255 : Franchissement potentiel de $FF ---------- ELSE ;---------- Début de la partie conditionnelle pour le cas START = 255 : Franchissement potentiel de $FF ---------- ;Attendre la position horizontale $00 à la position verticale $FF move.w #($FF<<8)!$00!$0001,(a0)+ ;WAIT 1st word (y ! x ! 1) move.w #$8000!($7F<<8)!$FE!$0000,(a0)+ ;WAIT 2nd word (BFD ! mask y ! mask x ! 0) ;---------- Fin de la partie conditionnelle pour le cas START = 255 : Franchissement potentiel de $FF ---------- ENDC IF (END>=255)&(255>=START) ;Car bogue dans ASM-One 1.20 : < est interprété comme <= ! ;---------- Début de la partie conditionnelle pour le cas (END >= 255) & (START <= 255) : Franchissement de $FF ---------- ;Pourquoi (END>=255)&(255>=START) ? Car le cas où START>255 implique que END>255 et donc qu'il n'y a pas franchissement de $FF : la partie du code précédent valable pour les lignes < $80, nécessairement précédé d'un $FFE1FFFE pour franchir $FF (ce WAIT est conditionné par START>255), permet de gérer sans problème la situation. ;On arrive donc ici quand on vient d'achever de tracer $FE et qu'après avoir attendu en $E0, le Copper considère donc que la ligne est $FF ;C'est la raison pour laquelle on a introduit la partie conditionnnelle quand START=255. Car sinon, on aurait déjà tracé $FF en arrivant ici ;(C) Sauter en (A) si la position verticale est < $FF move.w #($FF<<8)!$00!$0001,(a0)+ ;SKIP 1st word (y ! x ! 1) move.w #$8000!($7F<<8)!$00!$0001,(a0)+ ;SKIP 2nd word (BFD ! mask y ! mask x ! 1) move.w #COPJMP1,(a0)+ move.w #$0000,(a0)+ ;MOVE (COPJMP2) ;La position verticale est $FF. Attendre la position horizontale $3E à la position verticale $FF move.w #($FF<<8)!$3E!$0001,(a0)+ ;WAIT 1st word (y ! x ! 1) move.w #$8000!($7F<<8)!$FE!$0000,(a0)+ ;WAIT 2nd word (BFD ! mask y ! mask x ! 0) ;Exécuter les MOVE lea colors,a1 lea 40*2(a1),a1 REPT NB_MOVES move.w #COLOR00,(a0)+ move.w -(a1),(a0)+ ;#NB_MOVES MOVE (COLOR00) ENDR ;Si la dernière ligne est $FF, sauter en (E) IF END=255 ;---------- Début de la partie conditionnelle pour le cas END = 255 : Fin ---------- ;Pourquoi ne pas tester au Copper si $FF est la dernière ligne à tracer ? Parce qu'il est impossible d'élaborer un test qui fonctionne. En effet, au sortir des MOVE précédents, soit les MOVE étaient assez nombreux et $E0 a été dépassée et le Copper considère que la ligne est $00, soit ils ne le sont pas assez et il considère que la ligne est toujours $FF. On peut aligner les deux cas en rajoutant un WAIT en $E0 après le second (d'ailleurs c'est ce qu'on fait plus loin). Bref, on se trouve alors dans la situation où le Copper considère que la ligne est $00 après avoir tracé $FF. Mais alors quel test pour savoir si $FF est la dernière ligne ? Un SKIP en (END&$FF) permettant d'enjamaber un COPJMP en (D) va fonctionner ainsi : ;si END=255, on teste si $00>=$FF => échoue donc COPJMP : ok ;si END=256, on teste si $00>=$00 => réussit donc COPJMP évité : ok ;si END=257, on teste si $00>=$01 => échoue donc COPJMP : nok ;on voit qu'il est impossible de concilier échec/réussite du SKIP et le saut/pas saut attendu. Pour cette raison, on décide de faire un code conditionnel pour sortir de la boucle sur END=255 move.l a0,d0 IF 38>NB_MOVES addi.l #(7+NB_MOVES+3)*4,d0 ELSE addi.l #(6+NB_MOVES+2)*4,d0 ENDC move.w #COP1LCL,(a0)+ move.w d0,(a0)+ ;MOVE (COP1LCL) swap d0 move.w #COP1LCH,(a0)+ move.w d0,(a0)+ ;MOVE (COP1LCH) move.w #COPJMP1,(a0)+ move.w #$0000,(a0)+ ;MOVE (COPJMP1) ;---------- Fin de la partie conditionnelle pour le cas END = 255 : Fin ---------- ENDC ;Attendre la fin de la ligne $FF à la position horizontale $E0, donc la ligne suivante $00 ;EN FAIT c'est même après 39 MOVE et c'est pour ça que j'ai transformé les tests en 38>NB_MOVES ! VOIR TEST.S ;ce test n'est pas nécessaire pour NB_MOVES>=40, et il est même nuisible. En effet, après 40 MOVE à partir de $3E sur la ligne $FF, le raster n'est qu'en $DE mais le Copper n'a pas le temps d'exécuter ce WAIT avant qu'il ne franchisse $E0. Or quand le raster franchi $E0, le Copper considère que la ligne courante est devenue la ligne suivante, donc que le raster n'est plus sur la ligne $FF mais la ligne $00 (le tracé de la ligne $FF n'est pas terminé, mais le Copper ne se fonde pas sur cela dans son mécanisme de comparaison ; tout se passe comme s'il avait son propre compteur de ligne courante, incrémenté à chaque franchissement de $E0). Par conséquent, le Copper va interpréter ce WAIT comme un WAIT en $E0 sur la ligne $FF alors que la ligne courante serait $00, ce qui va le faire attendre tout une trame ! C'est pour cela qu'il faut conditionner ce WAIT IF 38>NB_MOVES move.w #($FF<<8)!$E0!$0001,(a0)+ ;WAIT 1st word (y ! x ! 1) move.w #$8000!($7F<<8)!$FE!$0000,(a0)+ ;WAIT 2nd word (BFD ! mask y ! mask x ! 0) ENDC ;Préparer l'adresse pour sauter en (A) move.l a0,d0 addi.l #2*4,d0 move.w #COP1LCL,(a0)+ move.w d0,(a0)+ ;MOVE (COP1LCL) swap d0 move.w #COP1LCH,(a0)+ move.w d0,(a0)+ ;MOVE (COP1LCH) ;(A) Attendre la position horizontale $3E à une position verticale quelconque mais < $80 (ie : 0xxxxxxx) move.w #($00<<8)!$3E!$0001,(a0)+ ;WAIT 1st word (y ! x ! 1) move.w #$8000!($00<<8)!$FE!$0000,(a0)+ ;WAIT 2nd word (BFD ! mask y ! mask x ! 0) ;Exécuter les MOVE lea colors,a1 lea 40*2(a1),a1 REPT NB_MOVES move.w #COLOR00,(a0)+ move.w -(a1),(a0)+ ;#NB_MOVES MOVE (COLOR00) ENDR ;Attendre la fin de la ligne à la position horizontale $E0 à une position verticale quelconque mais < $80 (ie : 0xxxxxxx), donc la ligne suivante IF 38>NB_MOVES ;Car bogue dans ASM-One 1.20 : < est interprété comme <= ! move.w #($00<<8)!$E0!$0001,(a0)+ ;WAIT 1st word (y ! x ! 1) move.w #$8000!($00<<8)!$FE!$0000,(a0)+ ;WAIT 2nd word (BFD ! mask y ! mask x ! 0) ENDC ;---------- Fin de la partie conditionnelle pour le cas (END >= 255) & (START <= 255) : Franchissement de $FF ---------- ENDC ;(D) Sauter en (A) si la position verticale est < ((END + 1) & $FF) move.w #(((END+1)&$FF)<<8)!$00!$0001,(a0)+ ;SKIP 1st word (y ! x ! 1) move.w #$8000!($7F<<8)!$00!$0001,(a0)+ ;SKIP 2nd word (BFD ! mask y ! mask x ! 1) move.w #COPJMP1,(a0)+ move.w #$0000,(a0)+ ;MOVE (COPJMP1) ;(E) Restaurer l'adresse de la Copper list pour la prochaine trame move.l copperList,d0 move.w #COP1LCL,(a0)+ move.w d0,(a0)+ ;MOVE (COP1LCL) swap d0 move.w #COP1LCH,(a0)+ move.w d0,(a0)+ ;MOVE (COP1LCH) ;Couleur de fond à noir move.w #COLOR00,(a0)+ move.w #$0000,(a0)+ ;Fin move.l #$FFFFFFFE,(a0) ;---------- Programme principal ---------- ;Rétablir les DMA move.w #$8380,DMACON(a5) ;DMAEN=1, BPLEN=1, COPEN=1 ;Activer la Copper list move.l copperList,COP1LCH(a5) clr.w COPJMP1(a5) ;Boucle principale move.l bitplane,a0 movea.l a0,a1 REPT 10 move.l #$FFFFFFFF,(a1)+ ENDR lea (128-DISPLAY_Y)*(DISPLAY_DX>>3)(a0),a1 REPT 10 move.l #$AAAAAAAA,(a1)+ ENDR lea (255-DISPLAY_Y)*(DISPLAY_DX>>3)(a0),a1 REPT 10 move.l #$AAAAAAAA,(a1)+ ENDR lea (DISPLAY_DY-1)*(DISPLAY_DX>>3)(a0),a1 REPT 10 move.l #$FFFFFFFF,(a1)+ ENDR lea (START-DISPLAY_Y)*(DISPLAY_DX>>3)(a0),a1 REPT 10 move.l #$F0F0F0F0,(a1)+ ENDR lea (END-DISPLAY_Y)*(DISPLAY_DX>>3)(a0),a1 REPT 10 move.l #$F0F0F0F0,(a1)+ ENDR _loop: btst #6,$BFE001 bne _loop ;---------- Finalisations ---------- ;Couper les interruptions hardware et les DMA move.w #$7FFF,INTENA(a5) move.w #$7FFF,INTREQ(a5) move.w #$07FF,DMACON(a5) ;Rétablir les interruptions hardware et les DMA move.w dmacon,d0 bset #15,d0 move.w d0,DMACON(a5) move.w intreq,d0 bset #15,d0 move.w d0,INTREQ(a5) move.w intena,d0 bset #15,d0 move.w d0,INTENA(a5) ;Rétablir la Copper list lea graphicslibrary,a1 movea.l $4,a6 jsr -408(a6) move.l d0,a1 move.l 38(a1),COP1LCH(a5) move.l 50(a1),COP2LCH(a5) clr.w COPJMP1(a5) jsr -414(a6) ;Libérer la mémoire movea.l bitplane,a1 move.l #DISPLAY_DY*(DISPLAY_DX>>3),d0 movea.l $4,a6 jsr -210(a6) movea.l copperList,a1 move.l #COPPERLIST,d0 movea.l $4,a6 jsr -210(a6) ;Rétablir le système movea.l $4,a6 jsr -138(a6) ;Dépiler les registres movem.l (sp)+,d0-d7/a0-a6 rts ;---------- Données ---------- graphicslibrary: dc.b "graphics.library",0 even copperList: dc.l 0 bitplane: dc.l 0 dmacon: dc.w 0 intena: dc.w 0 intreq: dc.w 0 colors: DC.W $0F00,$00F0,$000F,$0FFF,$0000,$0FF0,$0F0F,$00FF DC.W $0C00,$00C0,$000C,$0CCC,$0000,$0CC0,$0C0C,$00CC DC.W $0900,$0090,$0009,$0999,$0000,$0990,$0909,$0099 DC.W $0600,$0060,$0006,$0666,$0000,$0660,$0606,$0066 DC.W $0300,$0030,$0003,$0333,$0000,$0330,$0303,$0033