Trampolines For Embedded Systems by Joseph M. Link Listing One .text _Trampoline: moveml #0xC0C0,a7@- /* save d0,d1,a0,a1 on the stack */ movel #0xF0F0F0F0,a7@- /* save spot for passed int and */ movel #0xF0F0F0F0,a7@- /* pointer */ jsr 0xA0A0A0A0 /* call respective IrqHandler */ addql #8,a7 /* toss parm 1 and 2 */ moveml a7@+,#0x0303 /* restore d0,d1,a0,a1 from the stack */ rte TrampolineEnd: .globl _TRAMP_SIZE,_Trampoline _TRAMP_SIZE: .long TrampolineEnd-_Trampoline /***************************************************************/ extern char Trampoline[]; void IrqRegisterTramp(void (*func)(void *, int), void *arg1, int arg2, int vector) { unsigned char *p; p = malloc(TRAMP_SIZE); bcopy(Trampoline, p, TRAMP_SIZE); *((void *)(p + TRAMP_PARM1_OFFSET)) = arg1; /* plug in vales for handler */ *((int *)(p + TRAMP_PARM2_OFFSET)) = arg2; *((void *)(p + TRAMP_FUNC_OFFSET)) = func; vbr[vector] = (void *) p; /* register handler */ } Listing Two volatile unsigned long astRegister = 0; #define register_ast(mask) \ __asm__ volatile ("oril %1,%0" \ : /* no output */ \ : "m" (astRegister), "i" (mask)) /**********************************/ #define TICK 0x0001 /* bit mask to first bit of register */ void timerHandler(void *p, int i) { register_ast(TICK); } Listing Three /* if running in a loop, need to retrieve AST register and clear while IRQs disabled--else, we will pass astRegisterCopy as arg */ /* BEGIN loop only section */ IRQ_disable(); astRegisterCopy = astRegister; astRegister = 0; IRQ_enable(); /* END loop only section */ if(astRegisterCopy & TICK) { if(!unsleep()) /* wake up any tasks whose time is up */ tasks_rotate(); /* if no sleepers, round robin */ } if(astRegisterCopy & ETHERTXRDY) { /* any more data to send on ether?? */ . . . } if(astRegisterCopy & ETHERRXRDY) { /* we got data on ether, handle it */ . . . } Listing Four .text _Trampoline: moveml #0xC0C0,a7@- /* save d0,d1,a0,a1 on the stack */ movel #0xF0F0F0F0,a7@- /* save spot for passed int and */ movel #0xF0F0F0F0,a7@- /* pointer */ jsr 0xA0A0A0A0 /* call respective IrqHandler */ jmp common TrampolineEnd: common: addql #8,a7 /* toss parm1 and 2 */ movew a7@(16),d0 /* get sr from excep frame */ andiw #0x0700,d0 /* and skip asts if */ bneb DontSwitch /* there are pending interrupts */ tasb doingASTS /* or if */ bneb DontSwitch /* someone esle is handling asts */ testast: movew #0x2700,sr /* disable irqs */ tstl _astRegister /* any jobs to run? */ beqb NoASTs /* nope */ movel _astRegister,a7@- /* pass copy of astRegister */ clrl _astRegister /* and clear it */ movew #0x2000,sr /* enable all interrupts */ jsr _astHandler addql #4,a7 /* pop astRegister copy */ brab testast NoASTs: clrb doingASTS /* ok.. irqs still disabled */ moveal _pRunningTask,a0 /* get pointer to current task */ moveal _readyList,a1 /* get pointer to ptop */ cmpal a0,a1 /* and dont save if */ beqb DontSwitch /* pRunningTask == ptop */ SaveContext: moveml #0x3F3E,a7@- /* save d2-d7,a2-a6 on the stack */ movel a7,a0@ /* save stack pointer RestoreContext: first item in task struct */ moveal a1@,a7 /* point to ptops stack */ movel a1,_pRunningTask /* set runningTask to new task */ moveml a7@+,#0x7CFC /* restore d2-d7,a2-a6 from the stack */ DontSwitch: moveml a7@+,#0x0303 /* restore d0,d1,a0,a1 from the stack */ rte doingASTS: .byte 0x00 .globl _TRAMP_SIZE,_Trampoline _TRAMP_SIZE: .long TrampolineEnd-_Trampoline