Jump to content
IGNORED

GPU interrupt & GPU Object


swapd0

Recommended Posts

This is driving me crazy.

 

I have the GPU running into a tight loop waiting, here is the code:

	...
.wait_list:
    load (list_ptr),events
    cmpq #0,events
    jr EQ,.wait_list
    moveq #0,r0             ; don't f*ck parameters address at first iteration
	...

After that code I've inserted an infinite loop that changes the BG register.

 

When I run the program it works ok because I'm not writing anything into list_ptr (== 0 always), but when I put a GPUOB the GPU interrupt is executed and I leave it with this code (same as docs). And then the background color start to change (returns after the tight loop), this means that the last addqt (???) it's not needed? It's a must because without it, some times it hangs.

 

	...
; rte
    bclr #3,flags					; serviced
    bset #12,flags					; clear interrupt flag

	load (stack),rts
	addqt #4,stack
	addqt #2,rts					; ???
	jump (rts)
	store flags,(flagsAddr)			; restore interrupt

 

I don't know why this doesn't work, I've changed the way I was creating the OP list, and now I've a lot of problems when I've a GPU Object and some GPU code running.

 

Memory dump for the OP list without GPUOB.

Quote

OP list 240 bytes, start at 0000eb10

0000eb00 : 00000000 00000004   STOP

0000eb08 : 55555555 55555555

0000eb10 : 0000001d 600041c3   Jump if VC < top_line

0000eb18 : 0000001d 60008f33.   Jump if VC > bottom_line

0000eb20 : 01f4081d 663201c0.  Bitmap

0000eb28 : 00000002 80a0b00c

0000eb30 : 00c1581d 680001c0.  Bitmap

0000eb38 : 00008000 2008806c

0000eb40 : 00c2081d 6a000340.  Bitmap

0000eb48 : 0000a000 200880eb

0000eb50 : 00c3101d 6c040440.  Bitmap

0000eb58 : 00008000 2008906c

0000eb60 : 00c2101d 6e004540.  Bitmap

0000eb68 : 0000a000 200890ab

0000eb70 : 00c4b81d 70000640. Bitmap

0000eb78 : 00008000 4010a06c

0000eb80 : 00c5181d 72040740  Bitmap

0000eb88 : 0000a000 4010a0ab

0000eb90 : 00c5201d 74040840. Bitmap

0000eb98 : 00008000 8020b06c

0000eba0 : 00c5201d 7600c940. Bitmap

0000eba8 : 0000a000 8020b0ab

0000ebb0 : 00caa81d 78000a40. Bitmap

0000ebb8 : 00008001 0040c06c

0000ebc0 : 00d1281d 7a040b40. Bitmap

0000ebc8 : 0000a001 0040c0ab

0000ebd0 : 0113681d 7c228000. Bitmap

0000ebd8 : 00000000 2000414c

0000ebe0 : 00000000 00000004. STOP

0000ebe8 : 55555555 55555555

Memory dump OP List with GPUOB

OP list 240 bytes, start at 0000eb08
0000eb00 : 00000000 00000004 	STOP
0000eb08 : 0000001d 600041c3    Jump if vc < top_line
0000eb10 : 0000001d 60008f33    Jump if vc > bottom_line
0000eb18 : 00000000 00000002 	GPUOB
0000eb20 : 0115881d 663201c0 	Bitmap
0000eb28 : 00000002 80a0b00c 
0000eb30 : 00c1081d 68040290 	Bitmap
0000eb38 : 00008000 2008806c 
0000eb40 : 00c1081d 6a040410 	Bitmap
0000eb48 : 0000a000 200880eb 
0000eb50 : 00c2101d 6c040510 	Bitmap
0000eb58 : 00008000 2008906c 
0000eb60 : 00c2101d 6e040610 	Bitmap
0000eb68 : 0000a000 200890ab 
0000eb70 : 00c3181d 70040710 	Bitmap
0000eb78 : 00008000 4010a06c 
0000eb80 : 00c3181d 72040810 	Bitmap
0000eb88 : 0000a000 4010a0ab 
0000eb90 : 00c5201d 74040910 	Bitmap
0000eb98 : 00008000 8020b06c 
0000eba0 : 00c5201d 76040a10 	Bitmap
0000eba8 : 0000a000 8020b0ab 
0000ebb0 : 00c9281d 78040b10 	Bitmap
0000ebb8 : 00008001 0040c06c 
0000ebc0 : 00c9281d 7a040c10 	Bitmap
0000ebc8 : 0000a001 0040c0ab 
0000ebd0 : 0113681d 7c400000 	Bitmap
0000ebd8 : 00000000 2000414c 
0000ebe0 : 00000000 00000004 	STOP
0000ebe8 : 55555555 55555555 

 

Edited by swapd0
  • Confused 1
Link to comment
Share on other sites

Also, I've checked and I don't smash any register, the interrupt runs in the alternative register bank and the main GPU code runs in the other. 

 

Edit:

IMO the bug is when I return from the interrupt, the GPU doesn't return to the correct address.

 

Edited by swapd0
Link to comment
Share on other sites

There is not enough informations about how the interrupts routine is written to give a solution but, this is what i have done for my FACTS demo :

  • Main code use BANK1
  • Interrupt service code use BANK0

 

 Initialisation routine :

GPU_STACK				.equ	$F04000

; BANK0 :
;--------
OBJ_FLAGS				.equr	r22
vbl_counter				.equr	r26
vbl_interrupts			.equr	r27
pGflags					.equr	r28
cGflags					.equr	r29
cGstack					.equr	r30
pGstack					.equr	r31


;GPU initialisation
gpu_init:
	movei		#G_FLAGS,pGflags			;Flags GPU
	load		(pGflags),cGflags
	bclr		#3,cGflags
	bset		#7,cGflags					;enable op interrupt
	bset		#12,cGflags					;clear pending interrupt
	bclr		#14,cGflags					;select bank0
	store		cGflags,(pGflags)			;mise a jour des flags
	
	nop
	nop
	
;Stack Pointer
	movei		#GPU_STACK,pGstack			;adresse SP
	movei		#VblInterrupt,vbl_interrupts
	movei		#OBF,OBJ_FLAGS

	moveq		#0,vbl_counter

 

Service routine at slot 3 (GPU Object Interrupts):

gpu_int_3:
	jump		(vbl_interrupts)
	nop
	nop
	nop
	nop
	nop
	nop
	nop

 

GPU Object interrupt routine :

	.long
VblInterrupt:
	storew		r0,(OBJ_FLAGS)				;	Rr0		Rr22	|	-			|	-
	load		(pGflags),cGflags			;	Rr28			|	Cr22		|	-
	addq		#1,vbl_counter				;	#1		Rr26	|	Cr29		|	W(r22)
	load		(pGstack),cGstack			;	Rr31			|	Cr26		|	Wr29
	bclr		#3,cGflags					;	#3		Rr29	|	Cr30		|	Wr26
	addq		#2,cGstack					;	#2		Rr30	|	Cr29		|	Wr30
	addq		#4,pGstack					;	#4		Rr31	|	Cr30		|	Wr29
	bset		#12,cGflags					;	#12		Rr29	|	Cr31		|	Wr30
	jump		T,(cGstack)					;	T		Rr30	|	Cr29		|	Wr31
	store		cGflags,(pGflags)			;	Rr29	Rr28	|	-			|	Wr29
											;	-				|	Cr28		|	-
											;	-				|	-			|	W(r28)

In this exemple, I do those steps :

  • write to the OBF register as soon as possible to allow the OP to continue his process
  • read the GPU Flags register
  • increase the vbl counter
  • read the stack
  • clear the IMASK bit
  • correct the address of the instruction that will be executed after jumping
  • increase the stack pointer
  • clear the interrupt flag
  • jump to the new address
  • write back flags to register

 

 


 

  • Like 1
Link to comment
Share on other sites

Ok, this is my interrupt code. I'll have a look at your code to see what I'm doing wrong.

 

	.gpu

stack		.equr r31
flagsAddr	.equr r29
flags		.equr r28

rasterAddr	.equr r0
colors		.equr r1
clut		.equr r2
op			.equr r3
col			.equr r4

	.org G_RAM
	.macro EMPTY_IRQ
	.rept 8
	nop
	.endr
	.endm

; this is the entry point of the GPU code
cpu_interrupt:
;	IRQ 0
	movei #init_raster,r0		; 3
	movei #G_ENDRAM,stack		; 3
	jump t,(r0)					; 1
	moveta stack,stack			; 1

dsp_interrupt:
	EMPTY_IRQ
timer_interrupt:
	EMPTY_IRQ

op_interrupt:
	load (flagsAddr),flags			; GPU_FLAGS

	load (rasterAddr),colors
	movei #CLUT,clut

; 0, 1, 2, 3
	loadp (colors),col
	addqt #8,colors
	storep col,(clut)
	addqt #8,clut

	storew op,(op)					; restore op
	store colors,(rasterAddr)

; rte
    bclr #3,flags					; serviced
    bset #12,flags					; clear interrupt flag

	load (stack),r30
    addqt #4,stack
	addqt #2,r30
	jump (r30)
	store flags,(flagsAddr)			; restore interrupt

	.long
_raster_ptr::
	dc.l 0

init_raster:
	movei #G_FLAGS,flagsAddr
	movei #OBF,op
	movei #_raster_ptr,rasterAddr

	load (flagsAddr),flags
	bset #7,flags
	store flags,(flagsAddr)

    moveta rasterAddr,rasterAddr
	moveta op,op
    moveta flagsAddr,flagsAddr
    subqt #4,stack

; fall to next included file (must be gpu_events.s)

 

Link to comment
Share on other sites

if I put this  bset #14,flags instead of  bclr #14,flags it works...


I think that my jaguar init code it's wrong, I must something missing because sometimes it works, and other times it doesn't.

 

init_jag:
	move.w #$2700,sr                    ; disable all interrups
    move.w #$7fff,VI                    ; vbi off
	lea stack_top,sp

	lea dummy_irq,a0
	move.l a0,LEVEL0.w

	lea _BASE,a0
    move.l #$070007,d0                  ; big endian
    move.l d0,G_END-_BASE(a0)
    move.l d0,D_END
    moveq #0,d0
    move.l d0,G_CTRL-_BASE(a0)          ; stop gpu
    move.l d0,D_CTRL                    ; stop dsp
	move.l #1<<14|%11111<<9,G_FLAGS-_BASE(a0)	; disable GPU-IRQs, bank #1
;	move.l #1<<14|%11111<<9,D_FLAGS				; disable DSP-IRQs, bank #1
	move.l d0,D_FLAGS
	move.l #%11111100000000,J_INT          ; clear and disable IRQs

    move.l #list,d0
    swap d0
    move.l d0,OLP-_BASE(a0)             ; set OP to STOP-OBJECT

    moveq #0,d0
    move.w d0,R_DAC
    move.w d0,L_DAC
    move.w d0,OBF-_BASE(a0)             ; clear OP-Flag
    move.l d0,BORD1-_BASE(a0)           ; border black
    move.w d0,BG-_BASE(a0)              ; background black
    move.l d0,PIT0-_BASE(a0)            ; stop PIT
    move.l d0,JPIT1                     ; stop JPIT1
    move.l d0,JPIT3                     ; stop JPIT2
    move.w #$1F01,INT1-_BASE(a0)        ; clear pending irqs & enable vbl

; blitter init
    lea A1_BASE,a0
    lea B_CMD,a1
.cb0:
    move.l d0,(a0)+
    cmp.l a0,a1
    bne.s .cb0

    lea 4(a0),a0    ; skip B_CMD
    lea B_Z0+4,a1
.cb1:
    move.l d0,(a0)+
    cmp.l a0,a1
    bne.s .cb1

; video init
    move.w CONFIG,d0               ; Also is joystick register
    andi.w #VIDTYPE,d0             ; 0 = PAL, 1 = NTSC
    beq.s .pal

    move.w #NTSC_HMID,d2
    move.w #NTSC_WIDTH,d0
    move.w #NTSC_VMID,d6
    move.w #NTSC_HEIGHT,d4
    bra.s .calc_values

  .pal:
    move.w #PAL_HMID,d2
    move.w #PAL_WIDTH,d0
    move.w #PAL_VMID,d6
    move.w #PAL_HEIGHT,d4
  .calc_values:
    move.w d0,d1
    asr.w #1,d1                   ; Width/2
    sub.w d1,d2                   ; Mid - Width/2
    add.w #4,d2                   ; (Mid - Width/2)+4
    sub.w #1,d1                   ; Width/2 - 1
    ori.w #$400,d1                ; (Width/2 - 1)|$400
    move.w d1,HDE
    move.w d2,HDB1
    move.w d2,HDB2

    move.w d6,d5
    sub.w d4,d5

    move.w d5,VDB
    move.w #$FFFF,VDE

    move.l #0,BORD1                ; Black border
    move.w #0,BG                   ; Init line buffer to black

    move.w #PWIDTH4|CSYNC|BGEN|RGB16|VIDEN,VMODE-_BASE(a0)  ; Configure Video
	rts

dummy_irq:
    move.w #$101,INT1		; clear vbl interrupt and enable it
    move.w #0,INT2			; restore interrupts ***
    rte

 

Edited by swapd0
Link to comment
Share on other sites

Small update, I'm using this code instead of bset & bclr to initialize the GPU and it's more stable, at least it works always the same way but it crashes when I draw the sprites with the GPU, but never if I use de 68000 with GPUOBJ.

 

 

	movei #G_FLAGS,gpuFlagsPtr
	; init gpu
	movei   #(1<<7)+(1<<14),r1			; enable OBJ, reg page 1
    store r1,(gpuFlagsPtr)

 

Edited by swapd0
Link to comment
Share on other sites

Another small update.

 

I have a test program that draws several sprite with different bitmap depth, also I can scale some sprites. This is the part of the routine that check the sprite scale. if I remove this code, it it's more stable (It doesn't crash so often). So I think that with the GPUOBJ/OP Interrupts enabled, if there are some kind of pipeline stall it can break the code.

 

	...
	movei #$2020,r0
	cmp r0,scale
	jr EQ,continue_build_sprite
	moveq #31,tmp			; branch op
; check alignment
	and dst,tmp				; check 32bytes alignment
	movei #align_last_sprite,r20
	jump NE,(r20)
	bset #SCALE_BIT,fields	; branch op
continue_build_sprite:
	...

 

 

Edited by swapd0
Link to comment
Share on other sites

The code is a mix of C/68000 asm/GPU ams, without the toolchain you won't be able to compile it and it's a bit big. Although I'm doing the test with a small program, not the game, the library it's big.

 

Tomorrow I'll try something different, run the sprite engine with the 68000 with GPUOB interrupt and execute some "random" code in the GPU.

 

Edited by swapd0
Link to comment
Share on other sites

Ok, I got an event system running on the GPU, when I write an address into a GPU RAM location, starts to execute the functions written in that array, it's something like.

 

gpu_queue[0] = gpu_draw_sprite;
gpu_queue[1] = x;
gpu_queue[2] = y;
gpu_queue[3] = sprite_frame;
gpu_queue[4];
run_gpu_queue();		// something like gpu_queue_ptr = gpu_queue

 

If I load this code (gnu_shit_code) into the GPU and call it, it works fine without the GPUOB interrupts, but when I insert a GPUOB into the sprite list it hangs, sometimes very quickly sometimes it takes a while, I've to move the sprites with the joypad or it never hang.

 

If I don't tell the GPU to execute this code, it works (it's in a busy wait). So I think that my event system that I've been using in all my projects (4 in total) has some bugs. Looking at the code it could be done in a better way, more simple and without move pc, rx... , maybe this instruction is messing around.

 

 

_gpu_shit_code::
;    movei #$a0000,r0
;    load (r0),r0
.loop:
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
;rts
    moveq #4,r0			; skip 1 parameter
	load (r31),r1
	jump (r1)
	addqt #4,r31

 

Edited by swapd0
Link to comment
Share on other sites

My even dispatcher code:

; GPU events queue
; ptr to function [data]*
; ptr to function [data]*
; 0
; if a function has data, it must be read from r0 pointer

;    .include "jaguar/jaguar.inc"

    .globl _gpu_events_list
    .gpu

list_ptr    .equr r19
event_list  .equr r18
event       .equr r17
return      .equr r16

_gpu_events::
    movei #_gpu_events_list,list_ptr
    moveq #0,event                  ;
    store event,(list_ptr)          ; clear event list
.wait_list:
    load (list_ptr),event_list
    or event_list, event_list
    jr EQ,.wait_list
    nop

; execute events
.execute_event:

    load (event_list),event
    or event,event                  ; ptr == null, end of list, go to wait event list
    jr EQ,_gpu_events
    addqt #4,event_list             ; point to next event or data

    store event_list,(list_ptr)     ; save for next event
    move event_list,r0              ; parameters address

; jsr to routine
    movei #.l0,return
    subqt #4,r31
	jump (event)
	store return,(r31)

.l0:
; r0 will have number of words to skip
    movei #_gpu_events_list,list_ptr
    movei #.execute_event,event
    load (list_ptr),event_list
    jump (event)
    add r0,event_list               ; skip parameters

    .long
_gpu_events_list::
    dc.l 0  ; pointer to events list

 

My gpu interrupt code:

;	include "jaguar/jaguar.inc"

	.gpu

gpuFlagsPtr	.equr r29
flags		.equr r28

rasterAddr	.equr r1
colors		.equr r2
clut		.equr r3
opFlags		.equr r4
col			.equr r5

	.org G_RAM
	.macro EMPTY_IRQ
	.rept 8
	nop
	.endr
	.endm

cpu_interrupt:
;	IRQ 0
	movei #init_raster,r0		; 3
	jump t,(r0)					; 1
	nop							; 1
	nop							; 1
	nop							; 1
	nop							; 1

dsp_interrupt:
	EMPTY_IRQ
timer_interrupt:
	EMPTY_IRQ

op_interrupt:
	load (gpuFlagsPtr),flags			; GPU_FLAGS

	load (rasterAddr),colors
	movei #CLUT,clut

; 0, 1
	load (colors),col
	addqt #8,colors
	store col,(clut)
	addqt #4,clut

	storew r0,(opFlags)				; resume OP

	store colors,(rasterAddr)

; rte
    bclr #3,flags					; serviced
    bset #12,flags					; clear interrupt flag

	load (r31),r30
	addq #2,r30
    addqt #4,r31
	jump (r30)
	store flags,(gpuFlagsPtr)			; restore interrupt

	.long
_raster_ptr::
	dc.l 0

init_raster:
	movei #G_FLAGS,gpuFlagsPtr
	; init gpu

	movei #OBF,opFlags
	movei #_raster_ptr,rasterAddr

    moveta rasterAddr,rasterAddr
	moveta opFlags,opFlags
    moveta gpuFlagsPtr,gpuFlagsPtr

; fall to next included file (must be gpu_events.s)

Test code that does nothing.

_gpu_shit_code::
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
;rts
    moveq #0,r0			; skip 0 parameter
	load (r31),r1
	jump (r1)
	addqt #4,r31

 

Main code that tells the GPU to execute something.

 

		wait_gpu_idle();
		for ( int i = 0; i < 10; ++i )
		{
			wait_gpu_idle();
			gpu_queue[0] = (uint32_t)&gpu_shit_code;		// fn
			gpu_queue[1] = 0;
//			gpu_queue[2] = 0;			// with this uncommented takes more time to crash the code...
			run_gpu_queue();
			wait_gpu_idle();
		}

 

If I uncomment the gpu_queue[2] it takes more time to hang the jaguar, this means that r0 got some weird values so the event loop code fails? No, I'm testing the value of r0 after the execution of the event and is always 0.

 

Maybe I can try to port this code to a small 100% asm test code.

Edited by swapd0
Link to comment
Share on other sites

Ok, I think that I've found the bug. I call the GPU code from 6800 like this way. It hangs the Jaguar even if the loop it's executed only one time, but If I remove the last wait_gpu_idle(), it looks that never crashes.

 

Looks like you can't hammer a gpu address from the 68000 and the GPU at the same time, isn't it?

 

		for ( int i = 0; i < 10; ++i )
		{
			wait_gpu_idle();
			gpu_queue[0] = (uint32_t)&gpu_shit_code;		// fn
			gpu_queue[1] = 0;
//			gpu_queue[2] = 0;
			run_gpu_queue();
			wait_gpu_idle();
        }
_run_gpu_queue::
	move.l #_gpu_queue,_gpu_events_list
	rts

_wait_gpu_idle::
	lea _gpu_events_list,a0
.wait:
	moveq #127,d0
	divu #3,d0
	move.l (a0),d0
	bne.s .wait
	rts

	.long
_gpu_queue::
	ds.l 128

 

Edited by swapd0
Link to comment
Share on other sites

The 68000 writes to the GPU RAM in 16-bit segments, so two writes for a longword.

The GPU reads as 32bit, and is clocked higher.

 

It's reading only half the address (the high half)

 

You should be setting a sempahore flag, and checking that, not the actual pointer value.

 

.wait_list:
    load (list_ptr),event_list
    or event_list, event_list
    jr EQ,.wait_list
    nop

That is your problem.

  • Like 2
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...