		************************************
		*       /\/\                       *
		*      /    \                      *
		*     / /\/\ \ O R B_I D           *
		*    / /    \ \   / /              *
		*   / /    __\ \ / /               *
		*   ŻŻ     \ \ŻŻ/ / I S I O N S    *
		*           \ \/ /                 *
		*            \  /                  *
		*             \/                   *
		*     Feel the DEATH inside!       *
		************************************
		* Coded by:                        *
		* The Dark Coder / Morbid Visions  *
		************************************

* ATTENZIONE:
; Questo sorgente e` basato sulla Lezione11h4.s del Corso di Randy
; Mostra come effettuare il mascheramento anche per posizioni verticali
; in TUTTO lo schermo. Commenti alla fine del sorgente
; I credits per il sorgente originale sono di Randy - RJ
; Ehi Randy spero che non te la prendi se miglioro il tuo lavoro!
; Friendship RULEZ! :)))) (The Dark Coder)
 
	SECTION	DK,code
	incdir	"/include/"
	include	MVstartup.s		; Codice di startup: prende il
					; controllo del sistema e chiama
					; la routine START: ponendo
					; A5=$DFF000

		;5432109876543210
DMASET	EQU	%1000001010000000	; solo copper DMA

START:
	lea	$dff000,a5
	MOVE.W	#DMASET,$96(a5)		; DMACON - abilita bitplane, copper
					; e sprites.

	move.l	#COPPERLIST,$80(a5)	; Puntiamo la nostra COP
	move.w	d0,$88(a5)		; Facciamo partire la COP
	move.w	#0,$1fc(a5)		; Disattiva l'AGA
	move.w	#$c00,$106(a5)		; Disattiva l'AGA
	move.w	#$11,$10c(a5)		; Disattiva l'AGA

mouse:
	MOVE.L	#$1ff00,d1	; bit per la selezione tramite AND
	MOVE.L	#$13000,d2	; linea da aspettare = $130, ossia 304
Waity1:
	MOVE.L	4(A5),D0	; VPOSR e VHPOSR - $dff004/$dff006
	ANDI.L	D1,D0		; Seleziona solo i bit della pos. verticale
	CMPI.L	D2,D0		; aspetta la linea $130 (304)
	BNE.S	Waity1

	btst	#2,$dff016	; tasto destro premuto?
	beq.s	Mouse2		; se si non eseguire MuoviCopper

	bsr.s	MuoviCopper	; Routine che sfrutta il mascheramento del WAIT

mouse2:
	MOVE.L	#$1ff00,d1	; bit per la selezione tramite AND
	MOVE.L	#$13000,d2	; linea da aspettare = $130, ossia 304
Aspetta:
	MOVE.L	4(A5),D0	; VPOSR e VHPOSR - $dff004/$dff006
	ANDI.L	D1,D0		; Seleziona solo i bit della pos. verticale
	CMPI.L	D2,D0		; aspetta la linea $130 (304)
	BEQ.S	Aspetta

	btst	#6,$bfe001	; mouse premuto?
	bne.s	mouse
	rts

*****************************************************************************

MuoviCopper:
	move	PosBarra(pc),d0	; legge posizione Barra

	tst.b	SuGiu		; Dobbiamo salire o scendere? se SuGiu e'
				; azzerata, (cioe' il TST verifica il BEQ)
				; allora saltiamo a VAIGIU, se invece e' a $FF
				; (se cioe' questo TST non e' verificato)
				; continuiamo salendo (facendo dei subq)
	beq.w	VAIGIU

	cmp	#$34,d0		; confronta con il limite in alto
	sne	SuGiu		; setta di conseguenza il flag

; aggiorna posizione barra nella variabile e nella CLIST
	move	PosBarra(pc),d0
	subq	#1,d0
	move	d0,PosBarra
	move.b	d0,Barra	; scrive byte basso nella copperlist

; la seconda WAIT 255 deve essere attivata quando l'ultima riga della
; barretta si trova alla riga $FE, ovvero quando PosBarra=$fe-8
	cmp	#$fe-8,d0
	bne.s	.NoAttiva2		; se la barretta inizia ad attraversare
	move.b	#$ff,Attendi255_2	; riga 255 abilita la seconda WAIT 255
	bra.s	.change			; salta il controllo di riga $100
.NoAttiva2

; la prima WAIT 255 deve essere attivata quando la prima riga della
; barretta si trova alla riga $ff
	cmp	#$ff,d0
	bne.s	.NoDisattiva1		; se TUTTA la barretta ha attraversato 
	move.b	#$00,Attendi255_1	; riga 255, disattiva la prima WAIT 255
.NoDisattiva1

.change
	move	#$7f,d0
	bsr	AdjustClist

	move	#$ff,d0
	bsr	AdjustClist

	rts

VAIGIU:
	cmp	#$114,d0	; confronta con il limite in basso
	seq	SuGiu		; setta di conseguenza il flag

; aggiorna posizione barra nella variabile e nella CLIST
	move	PosBarra(pc),d0
	addq	#1,d0
	move	d0,PosBarra
	move.b	d0,Barra	; scrive byte basso nella copperlist

; la seconda WAIT 255 deve essere disattivata quando l'ultima riga della
; barretta si trova alla riga $FF, ovvero quando PosBarra=$ff-8
	cmp	#$ff-8,d0
	bne.s	.NoDisattiva2	; se la barretta inizia ad attraversare la
	move.b	#0,Attendi255_2	; riga 255 disabilita la seconda WAIT 255
	bra.s	.change		; salta il controllo di riga $100
.NoDisattiva2

; la prima WAIT 255 deve essere attivata quando la prima riga della
; barretta si trova alla riga $100
	cmp	#$100,d0
	bne.s	.NoAttiva1		; se TUTTA la barretta ha attraversato 
	move.b	#$ff,Attendi255_1	; riga 255, attiva la prima WAIT 255
.NoAttiva1

.change
	move	#$80,d0
	bsr	AdjustClist

	move	#$100,d0
	bsr	AdjustClist

	rts


Finito:
	rts

; variabili
PosBarra	dc.w	$34	; posizione barra
SuGiu:		dc.b	0	; flag direzione


*******************************
* Routine che corregge la CLIST
* D0 - riga target, cioe` riga che delimita l'ingresso in una diversa
* zona dello schermo.

	cnop	0,4
AdjustClist
	move	PosBarra(pc),d1	; coordinata prima riga barra
	move	d1,d2

	addq	#8,d2		; posizione ultima riga barra (sono 9 righe)
	cmp	d0,d2		; confronta con riga target
	blo.s	.exit		; se minore, la barra si trova TUTTA
				; al di sopra della riga target

	sub	d1,d0		; sottrae la pos dalla riga target
	blo.s	.exit		; se D1>D0, la barra si trova TUTTA
				; al di sotto della riga target

				; altrimenti la differenza ci dice
				; quale riga della barra ha posizione uguale
				; a quella della riga target.

; in D0 c'e` indicato il numero d'ordine della WAIT da modificare:
; moltiplica per 12, offset tra 2 WAIT
	asl	#2,d0
	move	d0,d1
	add	d0,d0
	add	d1,d0

	lea	PrimaWaitMascherata,a0
	bchg	#7,(a0,d0.w)
	
.exit
	rts
	
*****************************************************************************

	SECTION	GRAPHIC,DATA_C

COPPERLIST:
	dc.w	$100,$200
	dc.w	$180,$000	; Inizio la cop col colore NERO

	dc.w	$2c07,$FFFE	; una piccola barretta fissa verde
	dc.w	$180,$010
	dc.w	$2d07,$FFFE
	dc.w	$180,$020
	dc.w	$2e07,$FFFE
	dc.w	$180,$030
	dc.w	$2f07,$FFFE
	dc.w	$180,$040
	dc.w	$3007,$FFFE
	dc.w	$180,$030
	dc.w	$3107,$FFFE
	dc.w	$180,$020
	dc.w	$3207,$FFFE
	dc.w	$180,$010
	dc.w	$3307,$FFFE
	dc.w	$180,$000

Attendi255_1:
	dc.w	$00E1,$FFFE	; aspetta linea 255

BARRA:
	dc.w	$3407,$FFFE	; aspetto la linea $79 (WAIT NORMALE!)
				; questo wait e' il "BOSS" dei wait
				; mascherati seguenti, infatti lo seguono
				; come degli scagnozzi: se questo wait
				; scende di 1, tutti i wait mascherati
				; sottostanti scendono di 1, eccetera.

	dc.w	$180,$300	; inizio la barra rossa: rosso a 3

PrimaWaitMascherata:
	dc.w	$00E1,$80FE	; Questa WAIT attende la fine di una riga.
				; Si tratta di una WAIT con posizione
				; verticale mascherata. Poiche` questa
				; istruzione va eseguita DOPO la riga
				; $80, il bit alto (non mascherabile)
				; deve essere settato a 1.

	dc.w	$0001,$FFFE	; questa WAIT e` un istruzione "inutile"
				; infatti non blocca mai il copper.
				; Il suo scopo e` quello di far perdere
				; un po' di tempo al copper in maniera che
				; la seguente CMOVE venga eseguita quando
				; il pennello elettronico ha iniziato la
				; riga seguente.

	dc.w	$180,$600	; rosso a 6

	dc.w	$00E1,$80FE	; aspetta fine riga
	dc.w	$0001,$FFFE	; WAIT inutile che rallenta il copper

	dc.w	$180,$900	; rosso a 9

	dc.w	$00E1,$80FE	; aspetta fine riga
	dc.w	$0001,$FFFE	; WAIT inutile che rallenta il copper

	dc.w	$180,$c00	; rosso a 12

	dc.w	$00E1,$80FE	; aspetta fine riga
	dc.w	$0001,$FFFE	; WAIT inutile che rallenta il copper

	dc.w	$180,$f00	; rosso a 15 (al massimo)

	dc.w	$00E1,$80FE	; aspetta fine riga
	dc.w	$0001,$FFFE	; WAIT inutile che rallenta il copper

	dc.w	$180,$c00	; rosso a 12

	dc.w	$00E1,$80FE	; aspetta fine riga
	dc.w	$0001,$FFFE	; WAIT inutile che rallenta il copper

	dc.w	$180,$900	; rosso a 9

	dc.w	$00E1,$80FE	; aspetta fine riga
	dc.w	$0001,$FFFE	; WAIT inutile che rallenta il copper

	dc.w	$180,$600	; rosso a 6

	dc.w	$00E1,$80FE	; aspetta fine riga
	dc.w	$0001,$FFFE	; WAIT inutile che rallenta il copper

	dc.w	$180,$300	; rosso a 3

	dc.w	$00E1,$80FE	; aspetta fine riga
	dc.w	$0001,$FFFE	; WAIT inutile che rallenta il copper

	dc.w	$180,$000	; colore NERO

Attendi255_2:
	dc.w	$FFE1,$FFFE	; aspetta linea 255

	dc.w	$2007,$FFFE	; aspetto la linea $FD
	dc.w	$180,$00a	; blu intensita' 10
	dc.w	$2107,$FFFE	; linea seguente
	dc.w	$180,$00f	; blu intensita' massima (15)

	dc.w	$FFFF,$FFFE	; FINE DELLA COPPERLIST

	end

In questo esempio mostriamo come usare il mascheramento della posizione
verticale in TUTTO lo schermo. Abbiamo la solita barretta che stavolta si
muove lungo tutto lo schermo. Come sappiamo per usare le WAIT con Y maschera-
ta si deve porre il bit 8 della posizione specificata allo stesso valore della
posizione verticale in cui vogliamo che l'istruzione venga eseguita.
Per comodita`, nel seguito indicheremo come zona 1 dello schermo le righe
da 0 a $7F, zona 2 le righe da $80 a $FF e zona 3 le righe da $100 in poi.

Se abbiamo delle copperlist dinamiche tali che una WAIT mascherata puo`
essere eseguita in qualunque posizione dello schermo, l'unica possibilita`
e` quella di modificare "al volo" le WAIT mascherate. Come abbiamo detto
in skip1.s, rispetto al codice di Randy abbiamo sostituito delle WAIT
mascherate DC.W $0007,$80FE con delle semplici e NON mascherate WAIT
DC.W $0001,$FFFE che fanno la stessa cosa. In questo modo abbiamo dimezzato
il numero di WAIT mascherate presenti nella CLIST e di conseguenza anche
il numero di modifiche da fare! Nel nostro caso infatti dobbiamo modificare
solo delle WAIT che aspettano la fine di una riga. Quando dobbiamo aspettare la
fine di una riga nelle zone 1 o 3 dobbiamo avere DC.W $00E1,$80FE mentre nel
caso in cui aspettiamo in zona 2 ci serve DC.W $80E1,$80FE.
Quindi dobbiamo settare opportunamente il bit 8 di tale istruzione.

I piu` attenti si chiederanno subito:"Ma chi ce lo fa fare a sto' punto ad
usare la WAIT mascherate se dobbiamo modificare comunque la CLIST?".
L'osservazione e` giusta, infatti come ricorderete questo effetto puo`
essere realizzato anche con WAIT non mascherate, e il vantaggio delle WAIT
non mascherate e` proprio quello di non dover modificare TUTTE le WAIT ad ogni
frame. Tuttavia le modifiche da apportare alle WAIT non mascherate sono molto
minori. Infatti e` necessario invertire il bit 8 della posizione verticale
di una WAIT SOLAMENTE quando tale WAIT passa da zona 1 a zona 2 (o viceversa)
o quando passa da zona 2 a zona 3 (o viceversa), cosa che accade solo
occasionalmente. Inoltre, se come in questo caso la barretta si sposta di 1
sola riga ogni frame, e` evidente che di tutte le WAIT che compongono la
barretta al massimo UNA SOLA WAIT passera` da una zona all'altra. Riassumendo,
nel caso in cui utilizziamo delle WAIT non mascherate dobbiamo modificare
TUTTE le WAIT AD OGNI frame. Con le WAIT NON mascherate invece modifichiamo
UNA WAIT in POCHISSIMI frame. E` dunque evidente che le WAIT NON mascherate
sono ancora molto vantaggiose.

Vediamo la realizzazione pratica. Come detto ogni volta che una WAIT transita
da una zona ad un'altra dobbiamo cambiare un bit, ovvero possiamo semplicemente
invertirlo. Nel passaggio da zona 2 a zona 3, abbiamo un problema in piu`:
l'istruzione WAIT che aspetta la riga 255.

Vediamo per prima cosa come modificare le WAIT. Tutte le modifiche sono gestite
da un'unica routine che va bene in tutti i casi, alla quale viene passato come
parametro la riga "target" ovvero la riga che determina il passaggio da una
zona ad un'altra. Tale routine determina l'EVENTUALE passaggio di una delle
WAIT sopra la riga target e di conseguenza inverte lo stato del bit 8 della Y.
Notate che se SCENDIAMO dalla zona 1 alla zona 2, la riga target e` $80,
perche` non appena una WAIT viene eseguita sulla riga $80 il suo bit deve
essere settato a 1. Se invece SALIAMO dalla zona 2 alla zona 1 la riga target
diventa $7F, perche` non appena una WAIT viene eseguita sulla riga $80 il suo
bit deve essere settato a 0.
Ovviamente ad ogni iterazione la nostra routine (AdjustClist) deve essere
eseguita 2 volte, una volta per controllare il passaggio da zona 1 a zona 2
(o viceversa se andiamo nella direzione opposta) e una volta per controllare il
passaggio da zona 2 a zona 3 (o viceversa se andiamo nella direzione opposta).

Si potrebbe obiettare che dover eseguire (2 volte) questa routine puo` far
perdere il vantaggio di dover effettuare meno modifiche sulla CLIST (rispetto
al caso delle WAIT NON mascherate), ma non e` cosi`: infatti questa routine
ha un costo di esecuzione fisso, mentre nel caso delle WAIT NON mascherate
il numero di modifiche da fare e` pari al numero di righe che compongono la
barretta: pensate al caso di una barretta alta 60 righe!!
Inoltre la routine e` cortissima e` viene eseguita in CACHE (se c'e`) e fa
(eventualmente) un solo accesso alla CHIP (la modifica della clist), mentre
nel caso NON mascherato ogni modifica di una WAIT e` un accesso in CHIP.

Come detto, il passaggio da zona 2 a zona 3 ci pone un altro problema.
Nella copperlist in fatti c'e` una WAIT che attende la riga $FF (255).
E` evidente che se la nostra barretta si trova piu` in alto, tale WAIT deve
essere eseguita DOPO le istruzioni della barretta, mentre deve essere eseguita
prima se la barretta si trova in zona 3. Per risolvere questo problema
utilizziamo 2 WAIT che attendono tale riga, una prima e una dopo le istruzioni
della barretta e ne abilitiamo una alla volta. Come facciamo per disabilitare
e abilitare una WAIT? Semplice, basta modificarla mettendo come posizione Y 0
invece che 255 per disabilitarla, e rimettere 255 per abilitarla.
Notate che quando la barretta si trova in parte in zona 2 e in parte in
zona 3, nessuna delle 2 WAIT deve essere abilitata, perche` l'attesa di riga
255 e` fatta dalle WAIT dalla barretta stessa. Quindi (nel caso in cui si
scende da zona 2 a 3) quando la barretta si trova in zona 1 e 2 la prima WAIT
e` disabilitata e la seconda abilitata. Nel momento in cui l'ultima riga della
barra si trova alla riga $FF la WAIT dopo la barretta viene disabilitata,
fintanto che la barra si trova a cavallo tra le 2 zone entrambe le wait restano
disabilitate e quando la prima riga della barra si trova alla riga $100 la
prima WAIT viene abilitata. Nel caso in cui si sale queste azioni si succedono
in maniera opposta.
