ACPS5589@RYERSON.BITNET (George Borges) (01/31/89)
I need help. How can I install my own interrupt routine (in C) for the Ring Indicator line and the Carrier Detect line? Currently, my routines DO execute but the program bombs (usually two or three of them) immediately afterwards. Can anyone lead me to a source of info or post a small example program to demonstrate how Mfpint() works? Thx, George.
apratt@atari.UUCP (Allan Pratt) (02/01/89)
In article <8901302240.AA10005@ucbvax.Berkeley.EDU> ACPS5589@RYERSON.BITNET (George Borges) writes: > How can I install my own interrupt routine (in C) for the Ring Indicator > line and the Carrier Detect line? Currently, my routines DO execute but > the program bombs (usually two or three of them) immediately afterwards. You can't do it in C unless your compiler or library have some tricks. Specifically, C routines end with RTS (return from subroutine) while interrupt handlers need to end with RTE (return from exception). MWC has a library call, I think, which arranges for the calling procedure to end with RTE rather than RTS -- I think it plays games with the stack to achieve this. Check their documentation. However, the problem goes even deeper. Interrupt handlers must not change any registers (except SR; that's on the exception frame). Most C compilers can't be told to save & restore *all* the registers they use. Usually, if I *really* want to have the exception handler in C, I have a little assembly language to save registers, call the C procedure, then restore the registers and RTE: _ring: movem.l d0-d2/a0-a2,-(sp) ; alcyon clobbers these jsr _myring movem.l (sp)+,d0-d2/a0-a2 rte Then use "extern int ring()" and "Mfpint(xx,ring)" to install it. Better still, do the installation in assembly, so you can read & store the old handler's address, and restore it when you leave. Mfpint (foolishly) doesn't return the old value of the vector, so you can't use it to save & restore things. ============================================ Opinions expressed above do not necessarily -- Allan Pratt, Atari Corp. reflect those of Atari Corp. or anyone else. ...ames!atari!apratt
ACPS5589@RYERSON.BITNET (George Borges) (02/14/89)
----------------------------Original message----------------------------
Thanks to those two folks who replied to me. However, I *still*
cannot get Mfpint() to work properly. Perhaps I am somewhat dense.
Here's what I'm trying to do:
....
Jenabint( 14 ); /* enable ring indicator interrupt on MFP chip */
Mfpint( 14, interrupt ); /* set vector to point to my function */
... print stuff on screen in endless loop....
interrupt()
{
setrte(); /* in MWC 2.0 .. return from exception rather than rts */
Cconws("RING!!!");
}
.....
And that's basically it. I disable the interrupt after it occurs.
The interrupt routine *does* execute but my program bombs (usually 2 or 3
of them).
Can a knowledgeable soul help a fellow cretin in need? A fragment of working
C code would be most appreciated. Thanx
George Borges <ACPS5589@RYERSON.BITNET>
dag@per2.UUCP (Daniel A. Glasser) (02/16/89)
In article <8902140121.AA03228@ucbvax.Berkeley.EDU>, ACPS5589@RYERSON.BITNET (George Borges) writes: > ----------------------------Original message---------------------------- > Thanks to those two folks who replied to me. However, I *still* > cannot get Mfpint() to work properly. Perhaps I am somewhat dense. > Here's what I'm trying to do: > .... > Jenabint( 14 ); /* enable ring indicator interrupt on MFP chip */ > Mfpint( 14, interrupt ); /* set vector to point to my function */ > > ... print stuff on screen in endless loop.... > > interrupt() > { > setrte(); /* in MWC 2.0 .. return from exception rather than rts */ > Cconws("RING!!!"); > } > > And that's basically it. I disable the interrupt after it occurs. > The interrupt routine *does* execute but my program bombs (usually 2 or 3 > of them). > > George Borges <ACPS5589@RYERSON.BITNET> Okay, here's the straight dope from the dope who wrote the setrte function for MWC... You cannot safely use GEMDOS functions from within an interrupt routine. GEMDOS is not reentrant. The docs have the misleading language saying that the GEMDOS functions cannot be called recursively, but what they mean is that you cannot reenter GEMDOS while a GEMDOS function is in progress. When you trap to GEMDOS to do the Cconws you are entering GEMDOS. The GEMDOS trap handler puts the current context information into a fixed location, sets its own stack to another fixed location, and does what you asked. If a GEMDOS function is active when this happens, the return context gets overwritten as does the GEMDOS stack. This is not what you, or anybody else, wants. Although, technically, you can call BIOS and XBIOS functions from interrupt level routines, it is not a good idea in general. It is better to set flags for the application "user-mode" routines to deal with. The example in the MWC manual does use Cconws, but it is an example of how to catch a processor exception which will not occur in the execution of any GEMDOS routines (that I know of). Here is an example of how to use setrte() on an interrupt based on some external interrupt: short ringing; main() { ... Mfpint(14, interrupt); ringing = 0; Jenabint(14); for (;;) { ... while (ringing--) { /* don't wory about ints. */ Cconws("Ring!!!"); /* we'll catch it next time */ } ... } Jdisint(14); } interrupt() { setrte(); ++ringing; /* Atomic update */ } I've not had a chance to check this out, but it should work. Note also that your stack space is limited when you are in an interrupt routine. You don't know what you may be interrupting. Don't waste time in a interrupt routine. Daniel Glasser -- _____________________________________________________________________________ Daniel A. Glasser One of those things that goes uwvax!persoft!dag "BUMP!!!(ouch)" in the night. ---Persoft, Inc.---------465 Science Drive-------Madison, WI 53711-----------
blochowi@cat42.CS.WISC.EDU (Jason Blochowiak) (02/16/89)
It's been awhile since I've dealt with the low level stuff on the ST, but some general things: When enabling an interrupt, you almost always initialize the vector before you enable the interrupt. So, in this case, you'd do: { Mfpint(14,interrupt); Jenabint(14); } Also, it makes life easier if you use the constants included in the header files, e.g. "Mfpint(RING_INT,interrupt" (this is not a real constant, just an example). One possible reason for the routine bombing: You say that in your "other" routine (we'll call it "loop()"), you "...print stuff on screen in endless loop...". You then also try to print from within your interrupt routine. Perhaps there's a conflict? Even if there isn't, it'd probably be cleaner to set a flag, and then have loop() check it. So, we have: int rings; loop() /* Set the interrupt up & loop */ { rings = 0; /* Initialize the ring count */ Mfpint(14,interrupt); /* Install my ring handler */ Jenabint(14); /* Enable interrupt */ for (;;) /* Loop forever */ { if (!rings) /* If no rings, say so... */ printf("No rings...\n"); else /* Otherwise, show # of rings */ { printf("There've been %d rings\n",rings); rings = 0; } } } interrupt() { setrte(); /* MWC's function so we can rte instead of rts */ rings++; /* Increment the ring count */ } I didn't use Cconws because I didn't feel like dealing with printing a decimal conversion... Also, note that this code chunk doesn't deal with what would happen if there was a ring after the printf() in the else {}, but before the "rings = 0" statement - it would lose a ring. I hope this helped... ------------------------------------------------------------------------------ Jason Blochowiak (blochowi@garfield.cs.wisc.edu) "Not your average iconoclast..." ------------------------------------------------------------------------------
sommel@wn2.sci.kun.nl (Ron Sommeling) (02/17/89)
In article <825@per2.UUCP>, dag@per2.UUCP (Daniel A. Glasser) writes: > > Although, technically, you can call BIOS and XBIOS functions from interrupt > level routines, it is not a good idea in general. It is better to set flags > for the application "user-mode" routines to deal with. No, you can't safely call any BIOS or XBIOS function from within an interrupt. Take a look at the trap 13/14 trap-handler! Some registers are copied to an area pointed to by saveptr and then saveptr is updated. If an interrupt occurs after saving some registers in this area but before saveptr is updated, then the saved registers will be overwritten if you call BIOS/XBIOS routines in that interrupt. I can't see why Atari decided to save the registers in the area pointed to by saveptr instead of on the (supervisor)stack. If they did the latter then BIOS/XBIOS would be reentrant. Ron Sommeling email: sommel@wn2.sci.kun.nl
apratt@atari.UUCP (Allan Pratt) (02/23/89)
In article <336@wn2.sci.kun.nl> sommel@wn2.sci.kun.nl (Ron Sommeling) writes: > In article <825@per2.UUCP>, dag@per2.UUCP (Daniel A. Glasser) writes: > > > > Although, technically, you can call BIOS and XBIOS functions from interrupt > > level routines, it is not a good idea in general. It is better to set flags > > for the application "user-mode" routines to deal with. > > No, you can't safely call any BIOS or XBIOS function from within an > interrupt. That is not the case. You CAN call BIOS or XBIOS routines from interrupts. The way to do it is documented (in the documentation, of all places, not the disassembly!). You subtract 46 ($2e) from the system variable 'savptr' which is at $4a2. THEN you use the TRAP instruction. When the trap returns, you add $2e to savptr again. With this approach, one can write a BIOS call in C, because when the dispatcher calls the [X]BIOS function, the arguments are right on the stack, just as virtually all C compilers expect them to be. A couple of BIOS calls *are* written in C, notably Rwabs(). I don't know that I'd have made this decision if I'd designed the BIOS, but it does work, and it *is* reentrant, if you do what the documentation says to do. THIS IS NOT AN ENDORSEMENT OF USING BIOS FROM INTERRUPT LEVEL. If you find your program is doing that, re-think your program. There are not very many reasons to call BIOS like that, and a number of reasons not to: speed is the most important. Furthermore, NEVER ATTEMPT PRINTER OR DISK I/O FROM INTERRUPT LEVEL, because aside from the time it will take, timers and things aren't running. ============================================ Opinions expressed above do not necessarily -- Allan Pratt, Atari Corp. reflect those of Atari Corp. or anyone else. ...ames!atari!apratt