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

		.include        "jaguar.inc"
		.include        "gpuint.inc"
		.include        "joytrick.inc"

		.extern         InitGPU

		.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

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

		movei   #bg,r0          ; Previous value for BG
		movei   #BG,r1          ; Background Color Register
		load    (r0),r2         ; Load current 16-bit CRY
		addq    #1,r2

		store   r2,(r0)         ; Store it back
		storew  r2,(r1)

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


bg:             dc.l    0

		.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+$200

		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
