;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 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