;Programmé par Yragael pour Stash of Code (http://www.stashofcode.fr) en 2017.

;Cette œuvre 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.

;Dans cette version :
;- A la moitié de la hauteur de l'écran, le Copper passe la couleur à rouge ($0F00)
;- Au dernier quart de la hauteur de l'écran, le Copper passe la couleur à blanc ($0FFF) en déclenchant une interruption VERTB
;- Après la fin de la hauteur de l'écran, le hardware passe la couleur à bleu ($000F) en déclenchant une interruption VERTB
;- Au premier quart de la hauteur de l'écran, le CPU passe la couleur à vert ($00F0) en déclenchant une interruption VERTB
;Comme le gestionnaire d'interruption utilise un barillet (colors) pour modifier la couleur, la petite difficulté est de s'assurer qu'on active bien le Copper et la gestion des interruptions au bon moment pour que le scénario précédent soit déroulé correctement. Pour cela, il faut attendre la fin d'un VERTB et acquitter l'événement.

;---------- Directives ----------

	SECTION yragael,CODE_C

;---------- Constantes ----------

;Registres

VPOSR=$004
INTENA=$09A
INTENAR=$01C
INTREQ=$09C
INTREQR=$01E
DMACON=$096
DMACONR=$002
COLOR00=$180
COP1LCH=$080
COPJMP1=$088

;Programme

DISPLAY_Y=$2C
DISPLAY_DY=256
COPSIZE=4*4+4

;---------- 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 #COPSIZE,d0
	move.l #$10002,d1
	movea.l $4,a6
	jsr -198(a6)
	move.l d0,copperlist

;Couper le système

	movea.l $4,a6
	jsr -132(a6)

;Couper les interruptions hardware et les DMA

	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)

;Détourner les vecteurs d'interruption

	lea $64,a0
	lea vectors,a1
	REPT 6		;Les interruptions hardware génèrent des interruptions de niveau 1 à 6 correspondant aux vecteurs 25 à 30 pointant sur les adresses $64 à $78
	move.l (a0),(a1)+
	move.l #_rte,(a0)+
	ENDR

;---------- Copper list ----------

	move.l copperlist,a0

;Attendre la moitié de la hauteur de l'écran

	move.w #((DISPLAY_Y+((2*DISPLAY_DY)>>2))<<8)!$0001,(a0)+
	move.w #$FF00,(a0)+

;Passer la couleur à rouge ($0F00)

	move.w #COLOR00,(a0)+
	move.w #$0F00,(a0)+

;Attendre le dernier quart de la hauteur de l'écran

	move.w #((DISPLAY_Y+((3*DISPLAY_DY)>>2))<<8)!$0001,(a0)+
	move.w #$FF00,(a0)+

;Déclencher une interruption VERTB pour passer la couleur à jaune ($0FF0)

	move.w #INTREQ,(a0)+
	move.w #$8020,(a0)+

;Fin

	move.l #$FFFFFFFE,(a0)+

;---------- Programme principal ----------

;Attendre la fin d'un VERTB pour être certain de l'ordre dans lequel les couleurs seront utilisées : VERTB par CPU, Copper, VERTB via Copper, VERTB par hardware

_waitVERTB:
	move.l VPOSR(a5),d0
	lsr.l #8,d0
	and.w #$01FF,d0
	bne _waitVERTB

;Acquitter le dernier événement VERTB pour éviter qu'il ne déclenche l'interruption niveau 3 du CPU

	move.w #$0020,INTREQ(a5)

;Activer l'interruption VERTB

	move.l #_VERTB,$6C
	move.w #$C020,INTENA(a5)	;INTEN=1, VERTB=1

;Activer la Copper list

	move.l copperlist,COP1LCH(a5)
	clr.w COPJMP1(a5)
	move.w #$8280,DMACON(a5)	;DMAEN=1, COPEN=1

;Boucle principale
	
_loop:

;Attendre le premier quart de la hauteur de l'écran

_wait0:
	move.l VPOSR(a5),d0
	lsr.l #8,d0
	and.w #$01FF,d0
	cmp.w #DISPLAY_Y+((1*DISPLAY_DY)>>2),d0
	blt _wait0

;Déclencher une interruption VERTB pour passer la couleur à vert ($00F0)

	move.w #$8020,INTREQ(a5)

;Attendre une ligne suivante

_wait1:
	move.l VPOSR(a5),d0
	lsr.l #8,d0
	and.w #$01FF,d0
	bne _wait1		;Attendre la ligne 0 car le code prend moins de temps qu'il n'en faut au raster pour balayer les lignes DISPLAY_Y+DISPLAY_DY à 312 et donc reboucler sur la ligne 0

;Tester la pression du bouton gauche de la souris	

	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 vecteurs	d'interruption

	lea $64,a0
	lea vectors,a1
	REPT 6
	move.l (a1)+,(a0)+
	ENDR

;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)
	clr.w COPJMP1(a5)
	jsr -414(a6)

;Rétablir le système

	movea.l $4,a6
	jsr -138(a6)

;Libérer la mémoire

	movea.l copperlist,a1
	move.l #COPSIZE,d0
	movea.l $4,a6
	jsr -210(a6)

;Dépiler les registres

	movem.l (sp)+,d0-d7/a0-a6
	rts

;---------- Interruptions ----------

;VERTB

_VERTB:
	movem.l d0/a0,-(sp)		;Indispensable, mais à limiter aux registres modifiés

;Modifier la couleur 0

	lea colors,a0
	move.w (a0),COLOR00(a5)

;Cycler les couleurs

	move.w (a0),d0
	move.w 2(a0),(a0)+
	move.w 2(a0),(a0)+
	move.w d0,(a0)

;Acquitter l'événement VERTB

	move.w #$0020,INTREQ(a5)
	movem.l (sp)+,d0/a0		;Indispensable, mais à limiter aux registres modifiés
	rte

;Inhibition

_rte:
	rte

;---------- Données ----------

graphicslibrary:		DC.B "graphics.library",0
	EVEN
intena:		DC.W 0
intreq:		DC.W 0
dmacon:		DC.W 0
vectors:	BLK.L 6
copperlist:	DC.L 0
colors:		DC.W $00F0, $0FFF, $000F
color:		DC.w 3