Author |
Message |
- Joined: 17 Jun 2017
- Posts: 19
|
Accessing the VDP too fast during VBlank
Posted: Tue May 05, 2020 7:43 pm
|
Hi there,
I'm getting 'Accessing the VDP too fast' errors in Emulicious when calling an OUTI block during VBlank. I've read through a number of good VDP limit threads on the forum but can't work it out, so there must be something I still don't understand.
My VBlank handler at $0038 just satisfies the interrupt and jumps to the VBlank routine. This routine currently just blasts a SAT buffer to RAM by calling an OUTI block and it's one of these OUTI instructions that fails with the error. Interrupts are shown as disabled ('DI') in the side bar of the debugger. I've also tried switching the display off at the start of the routine before calling the OUTI block but this doesn't seem to work.
Is the OUTI block method still valid or does it violate VDP constraints even during VBlank? I was under the impression that writes during active display were the only ones I had to be worried about.
Thanks!
eljay
|
|
|
- Joined: 14 Apr 2013
- Posts: 623
|
Posted: Tue May 05, 2020 8:12 pm
|
eljay wrote Hi there,
I'm getting 'Accessing the VDP too fast' errors in Emulicious when calling an OUTI block during VBlank. I've read through a number of good VDP limit threads on the forum but can't work it out, so there must be something I still don't understand.
My VBlank handler at $0038 just satisfies the interrupt and jumps to the VBlank routine. This routine currently just blasts a SAT buffer to RAM by calling an OUTI block and it's one of these OUTI instructions that fails with the error. Interrupts are shown as disabled ('DI') in the side bar of the debugger. I've also tried switching the display off at the start of the routine before calling the OUTI block but this doesn't seem to work.
Is the OUTI block method still valid or does it violate VDP constraints even during VBlank? I was under the impression that writes during active display were the only ones I had to be worried about.
Thanks!
eljay
Hi eljay,
the OUTI block in the VBlank handler is fine as long as it doesn't take longer than VBlank. If you only write your SAT, it's not longer than VBlank.
Is it possible that you have line interrupts enabled and that you acknowledge a line interrupt instead of a frame (vblank) interrupt?
|
|
|
- Joined: 17 Jun 2017
- Posts: 19
|
Posted: Tue May 05, 2020 10:02 pm
|
No, line interrupts are showing as disabled in the VDP tab of the memory editor.
I was wrong before about disabling the display not fixing it. It seems to start working if I disable display at the start of VBlank and re-enable at the end. Is this necessary to do? I didn't think it was, so I wonder whether this is just masking the problem.
It also seems the OUTIs only error the first time around, every 4th OUTI or so, but if I skip the errors and continue past that initial frame it will then continue without errors for frames going forward. It suggests the first, and only the first, interrupt is happening while in active display but I can't see why. The display is off and interrupts disabled until just before starting the game loop, and the game loop then halts before doing anything. The VDP status flags returned on this problem interrupt are %1101 1111. After that they are %1001 1111.
My pseudo-code is:
.orga $38
push af
in a, ($bf) ; satisfy interrupt
jp vBlank
loop:
ei
halt
... small amount of logic
jp loop
vBlank:
... transfer sprites
; Return from interrupt
pop af
ret
|
|
|
- Joined: 14 Apr 2013
- Posts: 623
|
Posted: Tue May 05, 2020 10:25 pm
|
eljay wrote No, line interrupts are showing as disabled in the VDP tab of the memory editor.
I was wrong before about disabling the display not fixing it. It seems to start working if I disable display at the start of VBlank and re-enable at the end. Is this necessary to do? I didn't think it was, so I wonder whether this is just masking the problem.
It also seems the OUTIs only error the first time around, every 4th OUTI or so, but if I skip the errors and continue past that initial frame it will then continue without errors for frames going forward. It suggests the first, and only the first, interrupt is happening while in active display but I can't see why. The display is off and interrupts disabled until just before starting the game loop, and the game loop then halts before doing anything. The VDP status flags returned on this problem interrupt are %1101 1111. After that they are %1001 1111.
My pseudo-code is:
.orga $38
push af
in a, ($bf) ; satisfy interrupt
jp vBlank
loop:
ei
halt
... small amount of logic
jp loop
vBlank:
... transfer sprites
; Return from interrupt
pop af
ret
At the time the Vblank interrupt happens you still have your interrupts disabled. With interrupts disabled you won't execute the in a,($bf) at the beginning of your interrupt handler. So when the ei is executed the interrupt is still pending and taken. So at this point your interrupt handler isn't executed at the beginning of Vblank but later instead. And as it seems it is executed late enough to get your code to execute during active display.
You can fix this issue by inserting in a,($bf) before your loop.
|
|
|
- Joined: 05 Sep 2013
- Posts: 3757
- Location: Stockholm, Sweden
|
Posted: Wed May 06, 2020 2:11 pm
|
I would simply do:
vBlank:
... transfer sprites
; Return from interrupt
pop af
ei ; re-enable interrupts!
reti ; return from interrupt
so that next vblank interrupt will be triggered at the expected moment
also don't worry, interrupt can't be triggered on the instruction after EI so you'll get your reti executed *before* next IRQ
|
|
|
- Joined: 17 Jun 2017
- Posts: 19
|
Posted: Wed May 06, 2020 8:02 pm
|
Calindro wrote
You can fix this issue by inserting in a,($bf) before your loop.
Ooh, yes that fixes it, thanks! Does this mean vBlank is always happening behind the scenes (and setting the status flag) even if the display and interrupts are disabled in the VDP? I suppose that makes sense.
sverx wrote
I would simply do:
vBlank:
... transfer sprites
; Return from interrupt
pop af
ei ; re-enable interrupts!
reti ; return from interrupt
Thanks! Yes I'll do that as well.
|
|
|
- Joined: 05 Sep 2013
- Posts: 3757
- Location: Stockholm, Sweden
|
Posted: Thu May 07, 2020 3:39 pm
|
The VDP causes the IRQ(s) to be triggered only if the corresponding flag(s) is/are on.
But if they're ON and they get triggered when interrupts are disabled on the CPU (DI) then the interrupt service routine will be called later, when they'll be enabled again (EI).
That's what was happening here, you got your transfer sprites routine triggered as soon as you EI again, but you were no longer in vblank.
|
|
|
- Joined: 17 Jun 2017
- Posts: 19
|
Posted: Fri May 08, 2020 5:38 pm
|
sverx wrote The VDP causes the IRQ(s) to be triggered only if the corresponding flag(s) is/are on.
So the behaviour I'm seeing in Emulicious is that the VDP Status vblank flag gets set even though vblank isn't enabled in the VDP registers. Looking into it in the debugger it seems that it might be because vblanks are enabled by default on boot and disabling them in the VDP registers doesn't take effect until after the next frame, so the flag gets set once but not thereafter. Is this correct?
|
|
|