How to get out cleanly of an interrupt routine ?

Página 1/2
| 2

Por Metalion

Paladin (690)

Imagen del Metalion

08-02-2011, 11:19

Hi,

My interrupt management routine checks for the F1 key in order to put the game in pause. During that pause, I can press several keys in order to do "developer's" actions : view VRAM pages, enable/disable sprites, ... (within DI/EI opcodes).

I'd like to add a action key that would change levels within the game.
But this is a major branching process ... And it implies to get out of the interrupt routine quite cleanly.

My main game loop is as such :

L1:    call    LEVEL1
L2:    call    LEVEL2
...

What I have in mind is something like this (for example here a change from level 1 to level 2) :

change_level:        ; called from PAUSE routine (which is called from my main interrupt routine)
...
pop    hl            ; erases the last call (change_level) from SP
pop    hl            ; erases the last call (PAUSE) from SP
pop    hl            ; erases the last call (H.TIMI) from SP (since I put a "jp INTERRUPT" in that hook)
pop    hl            ; erases the last call (RST $38) from SP (but is this necessary ?)
pop    hl            ; erases the last call (LEVEL1) from SP
ld     hl,L2         ; let's go for a change to level 2
ex     (sp),hl
ei
jp     LEVEL2

What do you think Question

I guess I'll also have to add the "pop all registers" which will be missing from the last lines of the $38 routine ... Shocked!

EDIT : Yeah ... But what about all the calls made within the LEVEL1 routine ? Impossible to know about all of 'em ... oO

Login sesión o register para postear comentarios

Por Metalion

Paladin (690)

Imagen del Metalion

08-02-2011, 11:49

I just had an idea ...

Maybe I could save the SP address just at the beginning of each level.
That way, I could roll back the call stack it more easily ...

What do you think Question

Por Daemos

Paragon (1071)

Imagen del Daemos

08-02-2011, 12:46

I came up with the same idea.

So it might work. At the beginning of each level you indeed save the adress into a predefined space in RAM. Might just work.

Something like this

level1:
ld de,(sp)
ld hl,level
ld (hl),de

level:
db: ds 20 ;twenty levels to store..

then just add the level you want to load

;load level adress routine

ld hl,level
ld de,2 ;level 2
add hl,de

Then do the call to the obtained adress.

Thats how much I can make up with my limited skills Wink

Por ro

Prophet (3700)

Imagen del ro

08-02-2011, 13:35

here's a tip, don't use the ISR for that Wink

Por Daemos

Paragon (1071)

Imagen del Daemos

08-02-2011, 13:45

ISR?

Por Metalion

Paladin (690)

Imagen del Metalion

08-02-2011, 13:54

here's a tip, don't use the ISR for that Wink
Yeah ...
I'm beginning to think about that and maybe move all my "PAUSE" management routine out of the ISR.

However, saving the SP address at every beginning of a level might have been the solution, if it was to stay within the ISR. But I agree it's probably better to get it out of the ISR.

Por Metalion

Paladin (690)

Imagen del Metalion

08-02-2011, 13:55

ISR?
Interruptions Service Routine Tongue

Por hap

Paragon (1917)

Imagen del hap

08-02-2011, 20:06

What do you think QuestionVery confusing and prone to break stuff. I'd take some time designing a new solution and go with that. (use good old pen and paper if that's easier for you)

Por Edwin

Paragon (1175)

Imagen del Edwin

08-02-2011, 20:07

I'm beginning to think about that and maybe move all my "PAUSE" management routine out of the ISR.

I would leave it there. Pause is nothing more than disabling a number of features from you game routine. You want to have the ability to let some of them run. Maybe you want music to continue. Or some background animation.

The better way is to communicate something to the main routine. I don't know if you have something specific in there, but I often only check a few variables to see if something specific needs to be done. Like game over, next level, etc. The simplest way is to have a variable that you can change from the ISR. If the main routine finds some value there, it can act with the ISR guaranteed to be finished.

Something like:

    ei     ; start ISR
.loop:
    ld a,(VAR)
    dec a
    jp z,NEXT_LEVEL
    dec a
    jp z,GAME_OVER
    dec a
    jp z,NEXT_LIFE
    cp NUM_LEVELS
    jp c,GOTO_LEVEL
    jr .loop

Por Metalion

Paladin (690)

Imagen del Metalion

08-02-2011, 21:11

I would leave it there. Pause is nothing more than disabling a number of features from you game routine. You want to have the ability to let some of them run. Maybe you want music to continue. Or some background animation.
I still can, because I wrote my ISR the other way around : within the game, I set up a variable in RAM which does tell to the ISR what it has to manage. For example : bit 0 has the clock running, bit 1 is for the scrolling, bit 7 has the music play. That variable is checked by ISR at avery frame, and it does things accordingly.

So I still can manage the PAUSE routine outside the ISR and have the ISR continue to do things as I want. I simply change the variable at the beginning of PAUSE and restore it at the end.

Por Metalion

Paladin (690)

Imagen del Metalion

09-02-2011, 20:17

I finally moved my PAUSE management routine out of the ISR and into the main player command input routine.

But, much to my surprise, it is not easier to implement that way !

I still face the same problems for that main branching out, so I came up with the solution I described earlier : save the SP register in RAM at the beginning of each level, and then, when I need to change level (as a developer's action), I restore the SP register, erase the firt call address of the stack (call Level_x), calculate the entry point to the desired level, and then make a jp (hl).

I'll tell you tomorrow how that solution works.
It seems to be working fine on paper ...

Tongue

Página 1/2
| 2
My MSX profile