;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Jaguar Example Source Code
; Jaguar Workshop Series #6
; Copyright (c)1994 Atari Corp.
; ALL RIGHTS RESERVED
;
; Program: hv.cof   - GPU Interrupt Object Example
;  Module: hv_gpu.s   - GPU Interrupt Handler and Code Mover
;
		.include        "jaguar.inc"
		.include        "hv.inc"

		.globl		InitGPU

		.extern		main_obj_list
		.extern		bra2
		.extern		bm1
		.extern		bm2
		.extern		gpu1
		.extern		stop1
		.extern		bmp_highl1
		.extern		bmp_lowl1
		.extern		bmp_height2
		.extern		bmp_highl2
		.extern		bmp_lowl2
		.extern		scl_lowl2
		.extern		reflect1
		.extern		count_x1
		.extern		count_y1
		.extern		x_motion1
		.extern		y_motion1
		.extern		x_pos1
		.extern		y_pos1
		.extern		x_min1
		.extern		x_max1
		.extern		y_min1
		.extern		y_max1
		.extern		upd_freqx1
		.extern		upd_freqy1
		.extern		reflect2
		.extern		count_x2
		.extern		count_y2
		.extern		x_motion2
		.extern		y_motion2
		.extern		x_pos2
		.extern		y_pos2
		.extern		x_min2
		.extern		x_max2
		.extern		y_min2
		.extern		y_max2
		.extern		upd_freqx2
		.extern		upd_freqy2
		.extern		bmp_hscl2
		.extern		bmp_vscl2
		.extern		a_hdb
		.extern		a_hde
		.extern		a_vdb
		.extern		a_vde
		.extern		width
		.extern		height

		.text

InitGPU:
		movem.l a0-a2,-(sp)

		lea     gpu_code1,a0            ; Interrupt Dispatch Routine
		lea     _end_code1,a1
		move.l  #OP_INT,a2              ; Dest Address (GPU Int Object Handler)
		jsr     copy_block

		lea     gpu_code2,a0            ; GPU Interrupt Object Handler Code
		lea     _end_code2,a1
		move.l  #OP_HNDLR_ADDR,a2
		jsr     copy_block 

		lea     gpu_code3,a0            ; Set's up GPU and loops endlessly
		lea     _end_code3,a1
		move.l  #GPU_LOOP_ADDR,a2
		jsr     copy_block

		move.l  #G_OPENA,G_FLAGS        ; Enable GPU Interrupts from OP
		move.l  #GPU_LOOP_ADDR,G_PC     ; Address of GPU setup code
		move.l  #GPUGO,G_CTRL           ; Start GPU

		movem.l (sp)+,a0-a2
		rts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Procedure: copy_block
;	      Copies a block of memory in LONGwords (max 65536 bytes)
;
;         Inputs: 	a0.l	- Block Start
;			a1.l	- Block End
;
; Register Usage:	d0.w	- DBRA counter
;
; Stupid copy routine (use Blitter for large blocks of GPU code)

copy_block:
		move.l  d0,-(sp)
			
		move.l  a1,d0           ; End of block
		sub.l   a0,d0           ; Start of block

		lsr.l   #2,d0           ; # of LONGs
.copy_loop:
		move.l  (a0)+,(a2)+
		dbra    d0,.copy_loop

		move.l  (sp)+,d0
		rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Interrupt Dispatcher for Object Processor (GPU Interrupt Object) Interrupts

gpu_code1:
		.gpu
		.org    G_RAM+$30

		movei   #OP_HNDLR_ADDR,r0
		jump    T,(r0)
		nop


		.68000
_end_code1:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Interrupt Handler
; Increments the background color register every time interrupt occurs.

gpu_code2:
		.gpu
		.org            G_RAM+$80

		movei   #G_FLAGS,r30    ; Enable other ints
		load    (r30),r29
		bclr    #3,r29          ; Clear IMASK
		bset    #12,r29         ; Clear pending interrupt
		load    (r31),r28       ; Address of last instruction
		addq    #2,r28          ; +2 to point to next
		addq    #4,r31          ; Correct stack

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Move 1. bitmap object - first calculate x_pos2

		movei   #reflect1,r8      ; Adress of reflect in r8
		loadw   (r8),r9          ; Value of reflect in r9

		movei   #count_x1,r0      ; Adress of count_x in r0
		movei   #upd_freqx1,r3 	  ; Adress of upd_freqx in r3

		loadw   (r3),r1          ; Value of upd_freqx in r1

		movei   #donotx1,r3

		loadw   (r0),r2          ; Value of count_x in r2

		addq    #1,r2
		storew  r2,(r0)

		cmp     r1,r2            ; upd_freqx = count_x ?

		jump    MI,(r3)
		nop

		movei   #0,r2
		storew  r2,(r0)

		movei 	#x_pos1,r0        ; Adress of x_pos in r0
		movei 	#x_min1,r1        ; Adress of x_min in r1
		movei 	#x_max1,r2        ; Adress of x_max in r2
		movei 	#x_motion1,r3     ; Adress of x_motion in r3

		loadw   (r0),r4          ; Value of x_pos in r4
		loadw   (r1),r5          ; Value of x_min in r5
		loadw   (r2),r6          ; Value of x_max in r6
		loadw   (r3),r7          ; Value of x_motion in r7

		cmp     r5,r4            ; x_pos = x_min ?
		jr      NE,testxmax1
		nop

		xor     r9,r10
		storew  r10,(r8)
		neg     r7
		storew  r7,(r3)

testxmax1:
		cmp     r6,r4            ; x_pos = x_max ?
		jr      NE,nextxpos1
		nop

		xor     r9,r10
		storew  r10,(r8)
		neg     r7
		storew  r7,(r3)

nextxpos1:
		add     r7,r4
		storew  r4,(r0)          ; Store x_pos back to r0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Do same with y_pos1
;
donotx1:
		movei   #count_y1,r0      ; Adress of count_y in r0
		movei   #upd_freqy1,r3    ; Adress of upd_freqy in r3

		loadw   (r3),r1          ; Value of upd_freqy in r1

		movei   #donoty1,r3

		loadw   (r0),r2          ; Value of count_y in r2

		addq    #1,r2
		storew  r2,(r0)

		cmp     r1,r2            ; upd_freqy = count_y ?

		jump    MI,(r3)
		nop

		movei   #0,r2
		storew  r2,(r0)

		movei 	#y_pos1,r0        ; Adress of y_pos in r0
		movei 	#y_min1,r1        ; Adress of y_min in r1
		movei 	#y_max1,r2        ; Adress of y_max in r2
		movei 	#y_motion1,r3     ; Adress of y_motion in r3

		loadw   (r0),r4          ; Value of y_pos in r4
		loadw   (r1),r5          ; Value of y_min in r5
		loadw   (r2),r6          ; Value of y_max in r6
		loadw   (r3),r7          ; Value of y_motion in r7

		cmp     r5,r4            ; y_pos = y_min ?
		jr      NE,testymax1
		nop

		xor     r9,r10
		storew  r10,(r8)
		neg     r7
		storew  r7,(r3)

testymax1:
		cmp     r6,r4            ; y_pos = y_max ?
		jr      NE,nextypos1
		nop

		xor     r9,r10
		storew  r10,(r8)
		neg     r7
		storew  r7,(r3)

nextypos1:
		add     r7,r4
		storew  r4,(r0)          ; Store y_pos back to r0

donoty1:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Move 2. bitmap object - first calculate x_pos2

		movei   #reflect2,r8      ; Adress of reflect in r8
		loadw   (r8),r9          ; Value of reflect in r9

		movei   #count_x2,r0      ; Adress of count_x in r0
		movei   #upd_freqx2,r3 	  ; Adress of upd_freqx in r3

		loadw   (r3),r1          ; Value of upd_freqx in r1

		movei   #donotx2,r3

		loadw   (r0),r2          ; Value of count_x in r2

		addq    #1,r2
		storew  r2,(r0)

		cmp     r1,r2            ; upd_freqx = count_x ?

		jump    MI,(r3)
		nop

		movei   #0,r2
		storew  r2,(r0)

		movei 	#x_pos2,r0        ; Adress of x_pos in r0
		movei 	#x_min2,r1        ; Adress of x_min in r1
		movei 	#x_max2,r2        ; Adress of x_max in r2
		movei 	#x_motion2,r3     ; Adress of x_motion in r3

		loadw   (r0),r4          ; Value of x_pos in r4
		loadw   (r1),r5          ; Value of x_min in r5
		loadw   (r2),r6          ; Value of x_max in r6
		loadw   (r3),r7          ; Value of x_motion in r7

		cmp     r5,r4            ; x_pos = x_min ?
		jr      NE,testxmax2
		nop

		xor     r9,r10
		storew  r10,(r8)
		neg     r7
		storew  r7,(r3)

testxmax2:
		cmp     r6,r4            ; x_pos = x_max ?
		jr      NE,nextxpos2
		nop

		xor     r9,r10
		storew  r10,(r8)
		neg     r7
		storew  r7,(r3)

nextxpos2:
		add     r7,r4
		storew  r4,(r0)          ; Store x_pos back to r0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Do same with y_pos2
;
donotx2:
		movei   #count_y2,r0      ; Adress of count_y in r0
		movei   #upd_freqy2,r3    ; Adress of upd_freqy in r3

		loadw   (r3),r1          ; Value of upd_freqy in r1

		movei   #donoty2,r3

		loadw   (r0),r2          ; Value of count_y in r2

		addq    #1,r2
		storew  r2,(r0)

		cmp     r1,r2            ; upd_freqy = count_y ?

		jump    MI,(r3)
		nop

		movei   #0,r2
		storew  r2,(r0)

		movei 	#y_pos2,r0        ; Adress of y_pos in r0
		movei 	#y_min2,r1        ; Adress of y_min in r1
		movei 	#y_max2,r2        ; Adress of y_max in r2
		movei 	#y_motion2,r3     ; Adress of y_motion in r3

		loadw   (r0),r4          ; Value of y_pos in r4
		loadw   (r1),r5          ; Value of y_min in r5
		loadw   (r2),r6          ; Value of y_max in r6
		loadw   (r3),r7          ; Value of y_motion in r7

		cmp     r5,r4            ; y_pos = y_min ?
		jr      NE,testymax2
		nop

		xor     r9,r10
		storew  r10,(r8)
		neg     r7
		storew  r7,(r3)

testymax2:
		cmp     r6,r4            ; y_pos = y_max ?
		jr      NE,nextypos2
		nop

		xor     r9,r10
		storew  r10,(r8)
		neg     r7
		storew  r7,(r3)

nextypos2:
		add     r7,r4
		storew  r4,(r0)          ; Store y_pos back to r0

donoty2:
		movei   #0,r0
		movei   #OBF,r1         ; Write any value to OBF
		storew  r0,(r1)         ; to restart Object Processor

		jump    (r28)           ; Return to GPU
		store   r29,(r30)       ; Update GPU_FLAGS

		.68000
_end_code2:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; GPU Program Code (Setup and Loop)
;
; Originally, the following code was a simple infinite loop. The following
; method has been proven to be better for interrupt performance, however.
; In this case, the GPU watches a semaphore and loops while it's 0. In this
; example, it will always be 0.

gpu_code3:
		.gpu

		.org            G_RAM+$400

		movei   #ISTACK,r31     ; Initialize Interrupt Stack
gpu_loop:              
		movei   #semaphore,r10  ; Address of semaphore
		loadw   (r10),r11       ; Load value
		cmpq    #1,r11          ; Loop while not equal to 1

		jr      T,gpu_loop
		nop

		movei   #G_CTRL,r10     ; Shut off GPU; Note, in this
		load    (r10),r11       ; code, this should never happen.
		bclr    #0,r11
		store   r11,(r10)

semaphore:      .dc.l   0

		.68000
_end_code3:

		.end