;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 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 "hv4.inc" .globl InitGPU .extern count_x .extern count_y .extern x_motion .extern y_motion .extern x_pos .extern y_pos .extern x_min .extern x_max .extern y_min .extern y_max .extern upd_freqx .extern upd_freqy .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_pos movei #COUNT_BM,r8 movei #count_x,r12 ; Adress of 1. count_x in r12 outer_loop: movei #0,r11 move r12,r10 ; Adress of act. count_x in r10 inner_loop: move r10,r0 ; Adress of count_xy in r0 movei #COUNT_BM*20,r9 add r9,r10 move r10,r3 ; Adress of upd_freqxy in r3 loadw (r3),r1 ; Value of upd_freqxy in r1 movei #donotx,r3 loadw (r0),r2 ; Value of count_xy in r2 addq #1,r2 storew r2,(r0) movei #COUNT_BM*18,r9 ; Adress of next count_y cmp r1,r2 ; upd_freqxy = count_xy ? jump MI,(r3) nop movei #0,r2 storew r2,(r0) movei #COUNT_BM*12,r9 sub r9,r10 move r10,r0 ; Adress of xy_pos in r0 movei #COUNT_BM*4,r9 add r9,r10 move r10,r1 ; Adress of xy_min in r1 add r9,r10 move r10,r2 ; Adress of xy_max in r2 movei #COUNT_BM*12,r9 sub r9,r10 move r10,r3 ; Adress of xy_motion in r3 loadw (r0),r4 ; Value of xy_pos in r4 loadw (r1),r5 ; Value of xy_min in r5 loadw (r2),r6 ; Value of xy_max in r6 loadw (r3),r7 ; Value of xy_motion in r7 cmp r5,r4 ; xy_pos = xy_min ? jr NE,testxmax nop neg r7 storew r7,(r3) testxmax: cmp r6,r4 ; xy_pos = xy_max ? jr NE,nextxpos nop neg r7 storew r7,(r3) nextxpos: add r7,r4 storew r4,(r0) ; Store xy_pos back to r0 movei #COUNT_BM*2,r9 ; Adress of next count_y donotx: sub r9,r10 ; Point to next count_y movei #inner_loop,r0 addq #1,r11 cmpq #2,r11 jump NE,(r0) nop addq #2,r12 ; Point to next count_x movei #outer_loop,r0 subq #1,r8 cmpq #0,r8 jump NE,(r0) nop 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