- Joined: 28 Jan 2017
- Posts: 556
- Location: Málaga, Spain
|
Inconsistent state after interrupt
Posted: Sat Nov 25, 2023 11:22 pm
|
Ummmm....
I am playing with custom frame and line handlers, and I found many errors (Exceptions) in emulicious, of kind "Inconsistent state after interrupt: VRAM address changed from XXX to YYY)....
I know why this is happening.... and I am managing almost all troubles with this issue (timing things, as emulicious let me to know the line in which the exceptions happens) but the question is....
Can I make a interrupt VRAM safe??? I mean, to save the VRAM pointer at the start of the interrupt and restore it at its end... something like when you push a bank and pop it to return to the caller without causing a trouble.
Are there some thing which I am forgetting?
Regards.
|
- Site Admin
- Joined: 19 Oct 1999
- Posts: 14745
- Location: London
|
Posted: Sun Nov 26, 2023 8:40 am
|
It’s not necessarily wrong to leave the VDP state inconsistent unless you also have VDP access happening outside the interrupt, in an interruptible way. For example, if you are writing to VRAM during active display, an interrupt during that code would likely change the write address.
Avoiding this case is not simple, you can’t read back the VDP state and keeping track of it in RAM would slow things down.
|
- Joined: 28 Jan 2017
- Posts: 556
- Location: Málaga, Spain
|
Posted: Sun Nov 26, 2023 11:50 am
|
Thanks for the response, Maxim.
I am going to explain the problem, and the solultion I am applying.
In my engine, a game frame takes two screen frame loops (in all my games this is the usual), the loop is something like this:
while(true)
{
waitVblank();
update dynamic tiles in backtrounds and new tiles in borders due to scroll
do some things..... (weapon updates, player movement updates, etc.)
waitVblank();
load in real time 9 tiles for player animatioins
finish sprite loop, update Sprites in SAT and begin sprite loop
perform scrolling
do other things.... (enemies movement, mainly, and collisions between all kinds of objects)
}
and then... I have two custom functions (based on stage):
- One per frame custom handler (setting scroll to 0 to have a fixed data frame in top of screen, of three rows).
- One line custom handler. All the line based effects (mainly parallax scroll effects, or changing palette to do water like effects).
The thing is where to put the the functions which modify the VRAM in real time. My solution (after several weeks of testing) is to put all these VRAM sensible functions inside the interrupts, putting the rest of functions (mainly scripting of enemies, or the player movement logic) out of the interrupts.
More or less, is working, but was interested about keeping the VRAM state in the interrupts.
Regards.
|
- Joined: 06 Mar 2022
- Posts: 671
- Location: London, UK
|
Posted: Sun Nov 26, 2023 1:11 pm
|
Expanding on the points Maxim makes, feels to me like you basically have 3 options to keep things safe:
1. Put all the VRAM code inside interrupts
2. Put all the VRAM code outside interrupts
3. Disable interrupts around outside code blocks which manipulate VRAM
Option 1 also relies on you not allowing re-entrant interrupts (or at least don't re-enable interrupts until you've finished manipulating VRAM), and also implicit – in all three situations – is not manipulating VRAM in the NMI handler either.
I think you can't really write inherently safe (interruptible) code outside interrupts, since as Maxim points out you can never read the VRAM pointer state directly, and since setting the pointer and writing data are two non-atomic operations there's always the opportunity for an interrupt to split them up; so disabling interrupts or ensuring that your ISR is not going to affect the state are the only options it seems to me.
|
- Joined: 28 Jan 2017
- Posts: 556
- Location: Málaga, Spain
|
Posted: Sun Nov 26, 2023 1:53 pm
|
willbritton wrote Option 1 also relies on you not allowing re-entrant interrupts (or at least don't re-enable interrupts until you've finished manipulating VRAM
What I am doing is to assure that in the frame handler (from line 192) all the vram updating procedures are executed before the first line handler (in line 28).
willbritton wrote 3. Disable interrupts around outside code blocks which manipulate VRAM
I cannot do that, because I use both frame and first line interrupt to update the viewport x scroll for the top frame and the screens (they have scroll).
Fortunately, I have two screen refresh loops for one game frame, so I can make some vram updates in odd frames and others in even frames (although have to do, in the same frame, the sprites updates and the scroll update, to keep both sprites and background in sync).
This is a very interesing question, there are nice effects which can be done with this technique, but it is tricky for sure, to mix the timing requirements with a game platform engine (more in ansi c)!!!
Thanks guys for claryfing how the things work.
|
- Joined: 05 Sep 2013
- Posts: 3828
- Location: Stockholm, Sweden
|
Posted: Sun Nov 26, 2023 3:46 pm
|
nothing much to add here - basically the only safe way is to keep the (line) interrupts far away from where you access the VDP... which isn't always so easy :|
|