| While I was fiddling with interrupt handlers...

Previous | Graphics and Display |

Q:

I'm just fiddling around with interrupt handlers and don't understand why the following code won't work:

    void myInterruptHandler(void)
    {
      asm ("movem.l %d0-%d7/%a0-%a6,-(%sp)");
      // do something here...
      asm ("movem.l (%sp)+,%d0-%d7/%a0-%a6; rte");
    }

A:

There are two reasons for this. First, the sequence "do something here" surely uses some local variables. The compiler will put them in registers during the optimization, and it will generate code for saving them on the stack at the beginning of the procedure, before the execution of any statements in the function body. So, before executing

    asm("movem.l %d0-%d7/%a0-%a6,-(%sp)");

something will be pushed on the stack. Read this as "open brace '{' is not only the marker, it also generates an entry procedure code". So, when "rte" is encountered, the return address on the stack is trashed. Second, even if the procedure does not use any local vars, the entry code for the procedure is usually

    link #something,%a6

and the stack is again not suitable for executing "rte". Before release 2.2 of TIGCCLIB, the only universal and correct method for defining interrupt handlers was is to define a pure assembly auxilary procedure as follows:

    void InterruptHandler(void);  // Just a prototype
    asm ("myInterruptHandler:
          move.w #0x2700,%sr
          movem.l %d0-%d7/%a0-%a6,-(%sp)
          jbsr MainHandler
          movem.l (%sp)+,%d0-%d7/%a0-%a6
          rte");

    void MainHandler(void)
    {
      // Put everything you want here...
    }

To make life easier, starting from release 2.2, I introduced a new language extension called DEFINE_INT_HANDLER in the intr.h header file. Now, it is enough to write

    DEFINE_INT_HANDLER (myInterruptHandler)
    {
      // Put everything you want here...
    }