Using redirection vector table to jump interrupts to C func

Ask anything your want about Megadrive/Genesis programming.

Moderator: BigEvilCorporation

Post Reply
Milkybar
Newbie
Posts: 5
Joined: Wed Jul 18, 2012 1:57 pm

Using redirection vector table to jump interrupts to C func

Post by Milkybar »

Hi I am working with the TicTacToe C code sample to begin learning a little more about the lower levels of the system.

I understand that the interrupt vectors like vblank are fixed in ROM. The standard way of getting round this (as I understand) is storing a redirection vector table in RAM. Then the main interrupt routine looks up the dynamic vector in the RAM and adjusts the instruction pointer.

crt0.s

Code: Select all

        .data

.global vblank_vector
vblank_vector:
        .long   0
crt0.h

Code: Select all

extern unsigned int vblank_vector;
crt0.s

Code: Select all

vblank:
        move.l  vblank_vector,-(sp)
        beq.b   1f
		rts
1:
        addq.l  #1,gTicks
        addq.l  #4,sp
        rte
main.c

Code: Select all

void vblankcallback()
{
	put_str("Invoked from vector", 0x2000, 20-7, 2);
}

int main(void)
{
    vblank_vector = &vblankcallback;
    ...
}
As far as I can tell, callback is defiantly being made as the expected string is displaying on the screen. However following this all controller input is ignored. On further investigation it seems that while vblankcallback() is evoked it is not returning the instruction pointer or stack pointer (or something else correctly)

I have been trying may variations for several hours including placing instructions like __asm("rte") at the end of vblankcallback to try to end the interrupt but everything seems ineffective.

I their a proper way to redirect interrupts to C void return functions?
Chilly Willy
Very interested
Posts: 2993
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy »

Those vectors in crt0.s expect assembly functions - notice they don't save anything. The called function would also need to do rte, not rts. C functions expect the caller to have save at least d0-d1/a0-a1 and only do a rts, so simply sticking a C function in the vector will crash.

To use a C function, change the crt0.s like this:

Code: Select all

vblank:
        tst.l   vblank_vector
        beq.b   1f
        movem.l d0-d1/a0-a1,-(sp)
        move.l  vblank_vector,a0
        jsr     (a0)
        movem.l (sp)+,d0-d1/a0-a1
1:
        addq.l  #1,gTicks
        rte
Notice how we save and restore the volatile registers, do a normal call of the function (so it can return via rts), and then fall into the code that increments gTicks and does a rte.

If you want to pass an argument to the function, you would need code like this:

Code: Select all

vblank:
        tst.l   vblank_vector
        beq.b   1f
        movem.l d0-d1/a0-a1,-(sp)
        move.l  vblank_parameter,-(sp)
        move.l  vblank_vector,a0
        jsr     (a0)
        addq.l  #4,sp
        movem.l (sp)+,d0-d1/a0-a1
1:
        addq.l  #1,gTicks
        rte
Note that since this is a callback from an exception, the functions never return anything.
Milkybar
Newbie
Posts: 5
Joined: Wed Jul 18, 2012 1:57 pm

Post by Milkybar »

Thanks Chilly, I see my error now. I was confused that the sample code seemed to provide redirection vectors but did not actually use them.

So my basic error was that a C code will automatically store and recover volatile processor registers (d0-d1/a0-a1). However in a ASM function it is up to the programmer to take care of this.

So when calling a C code from inside ASM volatile registers should be stored before the call, and restored afterwards. So I assume any other registers used must also be stored and recovered?

In ASM this is OK as I can control what registered are used. Is their a way to determine what registers a C function will use?
Chilly Willy
Very interested
Posts: 2993
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy »

Milkybar wrote:Thanks Chilly, I see my error now. I was confused that the sample code seemed to provide redirection vectors but did not actually use them.

So my basic error was that a C code will automatically store and recover volatile processor registers (d0-d1/a0-a1). However in a ASM function it is up to the programmer to take care of this.
A C function saves and restores the NONvolatile registers, d2-d7/a2-a6. It's up to the caller to save the others. They're called volatile or scratch registers when they can be changed without saving, and nonvolatile when they must be saved. They are nonvolatile (unchanging) from the point of view of the caller.

So when calling a C code from inside ASM volatile registers should be stored before the call, and restored afterwards. So I assume any other registers used must also be stored and recovered?
An exception has to save and restore EVERYTHING it uses. The exception frame on the stack stores SR and PC, so the exception handler has to save/restore any other registers. In the case of a C function, d0-d1/a0-a1, and make sure that sp has the same value going out as it did coming in.

In ASM this is OK as I can control what registered are used. Is their a way to determine what registers a C function will use?
No. The compiler is free within the ABI to use ANY registers it needs to. The only thing the ABI says is if it uses any of d2-d7/a2-a6, those must be saved and restored. The ABI also says parameters are always passed as longs on the stack (like my parameter example).

To see exactly what registers it uses, you would need to have the compiler save the generated assembly instead of the generated object code. We do that here on the forum now and again to see how good/bad some compilers are at generating efficient code.
Milkybar
Newbie
Posts: 5
Joined: Wed Jul 18, 2012 1:57 pm

Post by Milkybar »

I understand that as an interrupt can occur at any time that stack and any processor registers must be returned to the state at the beginning of the interrupt, to allow normal execution to resume.

So if I intent to simply call a C function from an interrupt I need to manually store d0-d1/a0-a1 and the C function will take care of any non volatile registers that are used.

It also seems that RTE will restore the status register so that is another thing that can be ignored when coding interrupts.
Chilly Willy
Very interested
Posts: 2993
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy »

Yes. It seems you have it all straight now.
sigflup
Very interested
Posts: 111
Joined: Mon Sep 06, 2010 12:05 pm
Contact:

Post by sigflup »

I'm doing the exact same thing in my code. Btw, you don't have to write "vblank_vector = &vblankcallback;" you can just write "vblank_vector=vblankcallback;"
Post Reply