schmitz@fas.ri.cmu.edu (Donald Schmitz) (11/27/89)
I tried to mail this but our mailer gave up. Hope it is of general interrest: >The scenario: > I have a main routine and a counter interrupt handler both >which were written in C. I went into the assembly source for the >interrupt handler and changed RTS to RTE and placed an instruction to >save all the registers at the beginning of the routine and restore >them at the end. I'm also a beginner at 68000 assembly coding so I'm >not sure these are the correct commands. > > movem.l d0-d7/a0-a6,-(a7) /* save registers */ > disable_counter_interrupts > /* do any processing here > enable_counter_interrupts > movem.l (a7)+,d0-d7/a0-a6 /* restore registers */ > RTE > >When I have a very simple main routine with just a printf statement in it, >this works fine. I have a counter interrupt occuring every 200ms and >toggling a status light. When I add processing in the main loop >however, the interrupts seem to occur about 3 or 4 times and then the >processor seems to be off in the weeds somewhere. Whats going on here? Dave, It looks like you have done everything right, however it is hard to tell what your main program is doing to the state of processor, probably in some of the libraries like printf. One thing to try is to set the status register interrupt mask to 7 as soon as you enter the interrupt handler, ie. make the first instruction be: movw #2700,sr This will prevent your interrupt handler from being interrupted, by something like the uart being used by printf. This approach can lead to reduced performance if you are servicing lots of interrupts (low priority handlers lock out high priority ones), but it makes understanding what is happening much easier. Also, you should not have to save/unsave all of the registers, with some/(most ?) 68K C compilers you only have to save/unsave d0, d1, a0, and a1 in the code you patch in, the routine will save whatever else it uses itself. Next, are you sure the entire program is running in supervisor mode? If you aren't, the interrupt handler changes stack pointers on you, and you have to be sure both stack pointers are pointing into valid, separate stack spaces before you start everything. Another thing, is this really a 68000? 68020/68881 machines need more state saving because of the floating point unit. If this is the case, let me know and I'll send you sample code. Finally, there is an old hack to make this more transparent to a C program, it uses a bug/feature in the C pre-processor that seems to be fairly standard. Create a file reentrant.h that contains the following (this assumes the SUN C compiler/assembler, if you are using something different, you may have to change the instruction mnemonics or the asm() syntax). It is hard to understand what this does, but look at the code it generates and you will see what is going on, the macro generates a stub routine called by the exception/interrupt that in turn calls the C subroutine you write. /* ===============REENTRANT FUNCTION CALLS ON THE 68000============== Author: V.R.Pratt Date: Sept. 7, 1980. This package permits the use of the expression reentrant(fun) in place of the usual way to begin a function definition, namely fun() Invoking reentrant(fun) generates a self-contained function named 'fun' which pushes d0,d1,a0,a1 on the stack, calls '_fun', then pops a1,a0,d1,d0 back off the stack and does an 'rte' (return from exception). Example usage: reentrant(KbdServ) { return(ACIA1Data&0177); } ================================================================= */ #ifndef REENTRANT_H #define REENTRANT_H #define REENTRANT #define reentrant(fun) reentrant_(fun,_/**/fun, __/**/fun) #define reentrant_(fun,_fun,__fun)\ asm(" .text ");\ asm(" .globl _fun");\ asm("_fun:");\ asm(" movw #0x2700,sr");\ asm(" moveml a0/a1/d0/d1,sp@-");\ asm(" jsr __fun");\ asm(" moveml sp@+,a0/a1/d0/d1");\ asm(" rte");\ int fun();\ _fun() #endif REENTRANT_H ____ Now, in your C code, define your interrupt handler something like: #include <reentrant.h> reentrant(myhandler) { /* Your handler routine goes here */ } And to set up the interrupt handler, do something like: int * vec; main() { /* set up interrupt vector */ vec = (int *)(VECTOR * 4); /* get pointer into exception vector table */ *vec = (int)myhandler; /* now turn the interrupts on, and do the rest of the main stuff */ } If you have trouble with any of this, try to mail me more details. Don Schmitz - schmitz@fas.ri.cmu.edu