Forums

Sega Master System / Mark III / Game Gear
SG-1000 / SC-3000 / SF-7000 / OMV
Home - Forums - Games - Scans - Maps - Cheats - Credits
Music - Videos - Development - Hacks - Translations - Homebrew

View topic - Inconsistent state after interrupt

Reply to topic
Author Message
  • Joined: 28 Jan 2017
  • Posts: 556
  • Location: Málaga, Spain
Reply with quote
Inconsistent state after interrupt
Post 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.
  View user's profile Send private message
  • Site Admin
  • Joined: 19 Oct 1999
  • Posts: 14745
  • Location: London
Reply with quote
Post 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.
  View user's profile Send private message Visit poster's website
  • Joined: 28 Jan 2017
  • Posts: 556
  • Location: Málaga, Spain
Reply with quote
Post 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.
  View user's profile Send private message
  • Joined: 06 Mar 2022
  • Posts: 671
  • Location: London, UK
Reply with quote
Post 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.
  View user's profile Send private message Visit poster's website
  • Joined: 28 Jan 2017
  • Posts: 556
  • Location: Málaga, Spain
Reply with quote
Post 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.
  View user's profile Send private message
  • Joined: 05 Sep 2013
  • Posts: 3828
  • Location: Stockholm, Sweden
Reply with quote
Post 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 :|
  View user's profile Send private message Visit poster's website
Reply to topic



Back to the top of this page

Back to SMS Power!