Jump to content
IGNORED

GPU with mutiple interrupts


42bs

Recommended Posts

It does seem weird (but not unbelievable) that the GPU core would be buggy around interrupts but not the DSP, they're not identical, but I'd have expected them to be mostly similar.

 

What do you have running in the main loop whilst the interrupts are being fired? Perhaps try it with as minimal a main loop as possible? just a bunch of nops and a back to the start?

Link to comment
Share on other sites

I checked it. And yepp, in an idle loop (only reading joypad ports) no issue.

Added then some blitter code, still no issue.

It happens only during gameplay. There is a lot more stuff happening with the blitter.

Currently all happens redrawing happens in the VBL (not the interrupt, it just sets a flag).

 

I still suspect my code but it is getting very unlikely.

 

This really bugs me ;-) I do not like workarounds, they bite back someday.

Link to comment
Share on other sites

Perhaps try moving the game logic/pad reading etc, to the DSP and save the GPU for single fire stuff triggered from the DSP?

Wonder if maybe there is a particular instruction that an interrupt happening when it's processing causes the issue (like MOVEI), and as you say your code is just being unlucky.

Link to comment
Share on other sites

Perhaps try moving the game logic/pad reading etc, to the DSP and save the GPU for single fire stuff triggered from the DSP?

 

Wonder if maybe there is a particular instruction that an interrupt happening when it's processing causes the issue (like MOVEI), and as you say your code is just being unlucky.

I come closer. If I run my loop with VBL sync, no crash. If I remove the VBL sync and call my debug printhex (no blitter, plain GPU), it crashes. If I add some nop to my OBL interrupt code. It doesn't.

I guess the reason is that I delay the timer interrupt. VBL every 20ms, timer every 1ms.

 

I have to say: I am so happy I could buy a SKUNK board. Doing this with BJL only would be a hard thing.

  • Like 4
Link to comment
Share on other sites

Ah, so it could be that the 2nd interrupt is trying to fire whilst the first is still being serviced?

 

When you say you add some nops, how many? I have had issues with alignment in my code before and had to add in extra nop or force alignment. I am trying to remember exactly what the cause was as obviously all opcodes are 16bit..

 

Ah I *think* it was I was trying to load from a non long aligned address (jump table), which it turns out the JRISC isn't a huge fan of doing IIRC. I had the jump tables within the text section, so if I added a nop or single instruction then it would knock the table out of alignment and BOOM.

Skunks are nice, but I still think BJL has its place :) I am sure with a bit of work, some similar bi-directional comms for debug signalling could be achieved with BJL too (I too love having the ability to output hexdumps of registers/stacks etc from my debug libraries :D )

  • Like 2
Link to comment
Share on other sites

Ah, so it could be that the 2nd interrupt is trying to fire whilst the first is still being serviced?

 

When you say you add some nops, how many? I have had issues with alignment in my code before and had to add in extra nop or force alignment. I am trying to remember exactly what the cause was as obviously all opcodes are 16bit..

 

Ah I *think* it was I was trying to load from a non long aligned address (jump table), which it turns out the JRISC isn't a huge fan of doing IIRC. I had the jump tables within the text section, so if I added a nop or single instruction then it would knock the table out of alignment and BOOM.

 

Skunks are nice, but I still think BJL has its place :) I am sure with a bit of work, some similar bi-directional comms for debug signalling could be achieved with BJL too (I too love having the ability to output hexdumps of registers/stacks etc from my debug libraries :D )

 

I added 5 nops. But it is no alignment issue (I think). Because if I put the nopS outside the execution path, the same crash happens.

Yes, the GPU can only read 32bit aligned from internal RAM. I need to add a warning in lyxass as I fell into this trap as well.

 

Regarding BJL, it is actually bi-directional. On the ST I wrote debjag (a bugaboo clone). You could dump registers, memory, single-step, disassemble and even had a line-assembler.

But it is 68k so I never ported it to PC. BJL was planned as complete development tool-set. Well, the end of Atari came to early :(

Edited by 42bs
Link to comment
Share on other sites

The nops wouldn't have to be in the execution path, anywhere in text would shift the rest of the code on by 2-bytes. (which is how I first twigged the issue as changing non-called code broke or fixed the issue).

Yup exactly what I was meaning :) Update lo.exe to have a debug/console mode like skunk and some lib to run on the jag and bingo.

Atari will never die whilst we hack around with it! (well real Atari, not the sham that currently wields the name!)

  • Like 3
Link to comment
Share on other sites

Matthias gave me the hint to look into the DOOM sources. That's what they do:

    bclr    #3,r29              ; clear IMASK
    bset    #12,r29              ; and interrupt latch

    load    (r31),r28           ; get last instruction address
    move    R0_INTSTACK,r31        ; reset stack

So, they do not increment the stack pointer. Rather reset it. Which is what I do in my workaround.

I guess a clearer sign for a silicon bug is not possible. :-)

 

We should spread this as warning in the f0rum.

  • Like 2
Link to comment
Share on other sites

I guess they hit the problem on the GPU and just assumed it would be the same on the DSP. I am so glad it doesn't seem to be!

 

I wonder if the bug is the same on the different GPU versions.

 

Perhaps (in my instance anyway), as all the interrupts are timer based there is no issue, perhaps the external interrupts are the cause?

Link to comment
Share on other sites

I guess they hit the problem on the GPU and just assumed it would be the same on the DSP. I am so glad it doesn't seem to be!

 

I wonder if the bug is the same on the different GPU versions.

 

Perhaps (in my instance anyway), as all the interrupts are timer based there is no issue, perhaps the external interrupts are the cause?

 

Since the bug happens on high-frequency interrupts it should happen on the DSP early as the playback uses a 22kHz or 44kHz interrupt, right?

But I think even though the ISA is quiet equal, the DSP is different in so many parts, that it is likely the bug is only in the GPU.

If you just think of the bus width, memory size etc. . So I doubt they used the same RTL for both chips.

Link to comment
Share on other sites

 

Since the bug happens on high-frequency interrupts it should happen on the DSP early as the playback uses a 22kHz or 44kHz interrupt, right?

But I think even though the ISA is quiet equal, the DSP is different in so many parts, that it is likely the bug is only in the GPU.

If you just think of the bus width, memory size etc. . So I doubt they used the same RTL for both chips.

I've been following this thread.

I checked my code and I am doing what you were, not what DOOM is.

 

I have two interrupts turned on in the GPU, one from the OP, the other from the Blitter.

The OP interrupts once per vblank, the blitter interrupts ~10,000 times in a vblank.

 

So maybe it isn't a frequency problem as much as it is which interrupts are being used.

 

I've never used the timer interrupt with the GPU.

You said you were doing 1ms timer interrupts. (1000 times a second)

The Blitter is interrupting in the 60k to 80k times a second, and I've never seen this bug.

Link to comment
Share on other sites

I've been following this thread.

I checked my code and I am doing what you were, not what DOOM is.

 

I have two interrupts turned on in the GPU, one from the OP, the other from the Blitter.

The OP interrupts once per vblank, the blitter interrupts ~10,000 times in a vblank.

 

So maybe it isn't a frequency problem as much as it is which interrupts are being used.

 

I've never used the timer interrupt with the GPU.

You said you were doing 1ms timer interrupts. (1000 times a second)

The Blitter is interrupting in the 60k to 80k times a second, and I've never seen this bug.

 

Wow, I never found a use case for the blitter interrupt. I guess you are setting up a kind of task list and on every interrupt you setup another blitter job from this list?

 

And, yes, it is only a 1000 times :(

 

But good to know, that it should work.

Link to comment
Share on other sites

  • 5 months later...

I got some weird bug with my rasters.

 

This works.

start::
	movei #_hdma_colors,r0
	movei #CLUT,r2
	movei #G_FLAGS,r3
	movei #OBF,r4
	movei #G_ENDRAM-32,r31

	; enable OP interrupt
	load (r3),r29
	bset #7,r29
	store r29,(r3)

	moveta r0,r0
	moveta r2,r2
	moveta r3,r3
	moveta r4,r4
	moveta r31,r31
	movei #G_ENDRAM,r31

	nop
	nop
.loop:
	nop
	nop
	nop
	nop
	jr T,.loop
	nop

But if I remove the nop loop and have some normal code that touches the registers (I never move to the alternative bank), the rasters get random colours (r0 it's smashed and get some random memory)

Link to comment
Share on other sites

As for interrupts: r31/r30 get destroyed.

I learned the hard way that the "normal" way of stack handling is buggy.

Best is to reload the stack pointer instead of assuming it was decremented.

 

I use r31 as backup for r31.a (the actual interrupt stack pointer). I use two stacks, so the interrupts will not mess up with foreground subroutine calling.

 

My OP interrupt looks like this then:

IRQ_SP		REG 31

IRQ_SP.a	REG 31
IRQ_RTS.a	REG 30
IRQ_FLAGADDR.a	REG 29
IRQ_FLAG.a	REG 28

IRQScratch4.a	REG  4
IRQScratch3.a	REG  3
IRQScratch2.a	REG  2
IRQScratch1.a	REG  1
IRQScratch0.a	REG  0

;;; ----------------------------------------
;;; OBJECT interrupt
;;; ----------------------------------------
	org $f03030

	load	(IRQ_FLAGADDR.a),IRQ_FLAG.a
	movei	#obj_irq,IRQScratch0.a
	bset	#12,IRQ_FLAG.a
	load	(IRQ_SP.a),IRQ_RTS.a
	jump	(IRQScratch0.a)
	bclr	#3,IRQ_FLAG.a

;; ....

;;; ----------------------------------------
;;; OBJECT interrupt
;;; ----------------------------------------
obj_irq::
	movefa	IRQ_SP,IRQ_SP.a   ; <<<<<<<<<<<<<<<<< reload SP, no SP++ !!!
	addqt	#2,IRQ_RTS.a
;---------------
	movei	#OBF,IRQScratch0.a
	storew	IRQScratch1.a,(IRQScratch0.a)		; resume OP
;---------------
	movei	#OBL,IRQScratch0.a
	movei	#OBL0,IRQScratch1.a
	movei	#AnzObjekte*4,IRQScratch2.a
	loadp	(IRQScratch1.a),IRQScratch3.a
.loop
	addq	#8,IRQScratch1.a
	subq	#1,IRQScratch2.a
	storep	IRQScratch3.a,(IRQScratch0.a)
	addqt	#8,IRQScratch0.a
	jr	nz,.loop
	loadp	(IRQScratch1.a),IRQScratch3.a
;---------------
.exit
	jump	(IRQ_RTS.a)
	store	IRQ_FLAG.a,(IRQ_FLAGADDR.a)

.a => register in alternative bank

[Edit:] I place the IRQ stack on top (as it is usually only 4 bytes deep), and the normal stack below, not vice versa.

Edited by 42bs
  • Like 1
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...