Re: A89: Re: Disabling Interrupts


[Prev][Next][Index][Thread]

Re: A89: Re: Disabling Interrupts




Hi!

> I am gonna redo that code since scott noveck informed me that
> you have to preserve certain registers...
> 
> void myHandler(void)
> {
>   asm("movem.l %d0-%d2/%a0-%a1,-(%sp)");
> 
>   // Your code
> 
>   asm("movem.l (%sp)+,%d0-%d2/%a0-%a1; unlk %a6; rte");
> }

This will not work always (more precisely, it will not work in any
serious example). See why. Assume that your interrupt handler needs
3 local variables, say a, b, c and d. You will do:

void myHandler(void)
{
  int a,b,c,d;
  asm("movem.l %d0-%d2/%a0-%a1,-(%sp)");

  // Your code, which plays with a, b, c and d.

  asm("movem.l (%sp)+,%d0-%d2/%a0-%a1; unlk %a6; rte");
}

The optimizer will conclude that it can keep a, b, c and d in 
registers, say d1, d2, d3 and d4 (although you didn't put 
"register" keyword). And it will do so. To preserve d3 and d4, 
the compiler will generate the following code (it assumes that
d0, d1 and d2 may be trashed by a function call), at the 
beginning of the function, BEFORE any explicite statement in
the function body:

movem.l %d3-%d4,-(%sp)

It means that this will be executed before

movem.l %d0-%d2/%a0-%a1,-(%sp)

The statement unlk %a6 will of course clear this from the 
stack, but d3 and d4 will not be restored properly. I.e, the
compiler will save them, but before any executable statement,
and restore code

movem.l (%sp)+,%d3-%d4

is, of course, AFTER rte. In other words, you need to save
ALL registers, because you can not know in advance what will
be trashed by the compiler. The compiler will save everything
which will be trashed, but BEFORE any statement in the
function body, and will restore everything AFTER the last
statement in the function body!

To say: the following handler will probably work:

void myHandler(void)
{
  asm("movem.l %d0-%d7/%a0-%a5,-(%sp)");

  // Your code

  asm("movem.l (%sp)+,%d0-%d7/%a0-%a5; unlk %a6; rte");
}

but this solution have the following drawbacks:

1) It is the ugly wasting of stack space, because the 
registers will probably be saved twice (once implicitely
by the compiler, and twice explicitely by movem statement).

2) This solution does not work if you compile the program
with -fomit-stack-frame option (like essential part of
DoorsOS) because there is no stack frame in this case,
and unlk a6 is then disasterous.

3) My suggested solution is much more reliable, because
you never know in advance what else the compiler may
generate in some cases BEFORE any executable statement
in the function body. Just due to these reasons, I have
terrible problems with implementing floating point
routines (I have problems just because the compiler
generated somewhat which was not expected by me, and I
searched for a way to prevent the compiler to do this -
a6 is a vital register for both the compiler and for
TIOS floating point routines: not so good).

4) Anyway, your solution (with the correction given above)
is only two bytes shorter than my proposed solution: I have
an extra bsr label, and you have an extra unlk a6. I don't
think that this is such terrible "wasting of space". I think
that drawbacks mentioned above are greater than "terrible
wasting of two bytes".

Cheers,

Zeljko Juric