Page 2 of 2

Re: Game loops and Vertical Blank interupts

Posted: Tue May 15, 2018 1:54 am
by Chilly Willy
You also need some protection around that code in the vblank to keep from getting recursion in the vblank int. Set a flag before changing the sr, and in the vblank routine, just do the dma and exit if the flag is set. The code after the game loop should clear the flag.

Re: Game loops and Vertical Blank interupts

Posted: Tue May 15, 2018 8:47 am
by Stef
Ah yeah indeed you should keep track you are inside the vint handler to avoid recursion if your vint code take more than one frame...

Re: Game loops and Vertical Blank interupts

Posted: Tue May 15, 2018 12:01 pm
by Miquel
Stef wrote:
Mon May 14, 2018 10:09 pm
Yeah i understand but just lowering interrupt mask level in SR register right after doDMAstuff and before jumping to gameloop should be enough to produce the same result, you can read/write SR register... or i'm missing something ?
When you are INSIDE an exception, can you attend another exception of the same priority (vint) or lower (hint)? I thought no, but maybe I'm mistaken... Let me search for it...

edit:
Ok! yes! interrupt priority mask is set to 6 inside vertical exception, so if I lower it to 3 again it will be able to attend more exceptions without doing a "rte", is that what do you mean ?
That simplifies things!

Re: Game loops and Vertical Blank interupts

Posted: Tue May 15, 2018 1:53 pm
by Miquel
It works! thanks Stef!

New version:

Code: Select all

reset:
	jsr initialization
	jmp backgroundTasks

vertException:
	tst.b gameState
	jeq 0f
	addq.w #1, framesLost
	rte
0:
	movem.l %d?/%a?, -(%sp)
	jsr doDMAThings
	move.b #1, gameState
	move.w #0x2300, %sr		/* enable exceptions */
	jsr gameLoop
	movem.l (%sp)+,%d?/%a?
	move.b #0, gameState
	rte
Chilly Willy wrote:
Tue May 15, 2018 1:54 am
You also need some protection around that code in the vblank to keep from getting recursion in the vblank int. Set a flag before changing the sr, and in the vblank routine, just do the dma and exit if the flag is set. The code after the game loop should clear the flag.
Correct! I already said that. Hope the new code suits you.

Re: Game loops and Vertical Blank interupts

Posted: Tue May 15, 2018 2:27 pm
by Stef
You made it in a brutal way (moving 0x23 directly to SR) but yeah that was the idea ;)
Also you can test gameState after the DMA processing (as it should never be set before).

Re: Game loops and Vertical Blank interupts

Posted: Tue May 15, 2018 3:20 pm
by Miquel
Stef wrote:
Tue May 15, 2018 2:27 pm
You made it in a brutal way (moving 0x23 directly to SR) but yeah that was the idea ;)
Which fields/flags you think worth of preserving? At this precise point condition codes (Z,X,...) are not useful at all and all the other ones I set them as I want to be.
Stef wrote:
Tue May 15, 2018 2:27 pm
Also you can test gameState after the DMA processing (as it should never be set before).
I disagree. You can't allow DMA jobs to be launched at any time because the data could be malformed (the exception can be launched when you are setting the data).
Perhaps if you could make the code in a way that only one instruction makes the difference between a job is fully queued or not...
Another problem is you will be updating only partially a frame... could be visual artefacts...

Re: Game loops and Vertical Blank interupts

Posted: Wed May 16, 2018 10:01 am
by Stef
Miquel wrote: Which fields/flags you think worth of preserving? At this precise point condition codes (Z,X,...) are not useful at all and all the other ones I set them as I want to be.
Well, just for security i would always prefer to just modify interrupt mask level part of register but indeed using 0x2300 should definitely not hurt here ;)
Miquel wrote: I disagree. You can't allow DMA jobs to be launched at any time because the data could be malformed (the exception can be launched when you are setting the data).
Perhaps if you could make the code in a way that only one instruction makes the difference between a job is fully queued or not...
Another problem is you will be updating only partially a frame... could be visual artefacts...
Well it's all up to your game logic. I guess the doDMAJobs(..) method use kind of DMA queue system. If only gameLoop actually queues data for DMA there is no use in separating them but if your main background loop is also queuing data then DMA should always happen here (or you will loss some precious DMA bandwidth).

Re: Game loops and Vertical Blank interupts

Posted: Wed May 16, 2018 8:27 pm
by Miquel
Queuing DMA jobs from the background "thread", that's really the problem!

I particularly use a buffer to queue commands and data to the vertical "thread". But I think I just have found a solution: use a MOVEM to fill that buffer all at once.

The only problem is, to perform DMA operation you need to set 7 registers, this way it will be setting 8... I need a trouble free writing to 0x00C00004... I think I could set any register to any value except the one that fires the dma...

Re: Game loops and Vertical Blank interupts

Posted: Wed May 16, 2018 11:51 pm
by Sik
Throw autoincrement into the mix. Usually you'd use 2, but if you want to write vertically to a tilemap you may want to use 128 (assuming 64×32 or 64×64), and for the horizontal scroll table you may want to use 4 so you can keep each plane separate in your buffers in RAM. And possibly some other uses. That should pad it out to eight words and provide an useful feature.

By the way: if you disable an interrupt and it tries to fire while disabled, then it'll fire immediately as soon as you reenable it, no matter how long it has taken to be reenabled. So you could use that as some sort of mutex from the background thread.

Re: Game loops and Vertical Blank interupts

Posted: Thu May 17, 2018 1:21 pm
by Chilly Willy
Yeah, I was going to mention that any time you write data to a structure (like a queue) that is read from an int, you NEED to disable ints while setting it, not just rely on "indivisible" instructions. Learned a lot about that while working on the Amiga. You don't need to fully disable ints in some cases, just the ones that use the queue. Unfortunately, SEGA got the priorities of the vblank and hblank backwards, so using the vbint means effectively disabling ints while working on critical structs. :( You could have done a lot more with vbints on the Genny if they had swapped the two priorities, making hblank 6 and vblank 4.

Re: Game loops and Vertical Blank interupts

Posted: Thu May 17, 2018 2:30 pm
by Sik
Disabling the vblank interrupt from the VDP itself (i.e. register $81xx) has the same delaying effect as masking it away with SR (i.e. it's not discarded). So yes, you can disable vblank without disabling hblank.

The implication of the above is that if you're enabling them for the first time then you better get ready to cope with an immediately firing interrupt that shouldn't have been there :v (so make sure to either dummy them out or that their side-effects are not dangerous)

Re: Game loops and Vertical Blank interupts

Posted: Thu May 17, 2018 2:42 pm
by Chilly Willy
Sik wrote:
Thu May 17, 2018 2:30 pm
Disabling the vblank interrupt from the VDP itself (i.e. register $81xx) has the same delaying effect as masking it away with SR (i.e. it's not discarded). So yes, you can disable vblank without disabling hblank.

The implication of the above is that if you're enabling them for the first time then you better get ready to cope with an immediately firing interrupt that shouldn't have been there :v (so make sure to either dummy them out or that their side-effects are not dangerous)
That's probably the better way to handle it if you use hblank ints, then. :D

Re: Game loops and Vertical Blank interupts

Posted: Thu May 17, 2018 7:43 pm
by Miquel
Chilly Willy wrote:
Thu May 17, 2018 1:21 pm
Yeah, I was going to mention that any time you write data to a structure (like a queue) that is read from an int, you NEED to disable ints while setting it, not just rely on "indivisible" instructions. Learned a lot about that while working on the Amiga. You don't need to fully disable ints in some cases, just the ones that use the queue.
In theory, after reading some documentation on Internet, the second group of interruptions, were vint and hint belong fires only after the finalization of the current instruction. So if you can queue with only one instruction you don't need to disable interrupts.

But in my case I also need to update a "pointer to next position", so that's what I ended up doing:

Code: Select all

move.w	#0x2700, %sr			/* disable exceptions */
move.l	pVideoBufferPos, %a0
movem.l	%d0-%d5, (%a0)			/* copy data to buffer */
lea	20(%a0), %a0
move.l	%a0, pVideoBufferPos
move.w	#0x2300, %sr			/* enable exceptions */
With that code I can setup a DMA job anywhere, then the vertical exception takes this buffer and begins to write directly, without any data manipulation, to vdp registers.

Re: Game loops and Vertical Blank interupts

Posted: Wed May 30, 2018 11:45 pm
by walker7
One thing a lot of NES games do is set a variable to $00 until VBlank has fired, and then during VBlank, it gets set to $FF. At the end of VBlank, it returns to $00. This could be easily adapted to the Sega Genesis.

This could be checked for at the beginning of the VBlank routine: If the flag is $00, make it $FF and run VBlank code. If the flag is $FF, immediately jump to the RTE (restoring registers if you saved them).

Re: Game loops and Vertical Blank interupts

Posted: Thu May 31, 2018 2:15 am
by Miquel
Unless I misunderstand you that's more or less how my last example works, or how SGDK works.

Since 68K has bit specialized instructions could be better to just use a bit of a variable.