UUCJEFF@ECNCDC.BITNET (06/16/88)
A few weeks ago a reader had a problem with outputing several midi bytes. I think he was trying to use the Xbtimer. I have later found out courtesy of Stefan Daystrom of Hybrid Arts that you cannot have any TOS, BIOS, or XBIOS calls inside an interrupt. You have to do whatever it is you want without the calls, this is due to the re-entrancy characteristics of the ST. Therefore, you cannot use Bconstat or Midiws from inside and Xbtimer interrupt. I was having the same problem, I was thinking it might have been the stack size, but replaced it with the same code that the system call would have done, (modifying it to fit the routine) and it works perfectly. I even save time by avoiding all the stack bookkeeping by the subroutine call. I got the code of those system calls from Abacus, you can also get them from the developer's kit. While this fact problem was explained somewhere in the docs, it would have been nice if they would have mentioned this in the docs of the Xbtimer call. Jeff, UUCJEFF@ECNCDC.BITNET
leo@philmds.UUCP (Leo de Wit) (06/20/88)
In article <8806151931.AA05945@ucbvax.Berkeley.EDU> UUCJEFF@ECNCDC.BITNET writes: >A few weeks ago a reader had a problem with outputing several midi bytes. >I think he was trying to use the Xbtimer. I have later found out courtesy >of Stefan Daystrom of Hybrid Arts that you cannot have any TOS, BIOS, or >XBIOS calls inside an interrupt. You have to do whatever it is you want without >the calls, this is due to the re-entrancy characteristics of the ST. >Therefore, you cannot use Bconstat or Midiws from inside and Xbtimer interrupt. > [14 lines deleted, says vi 8-] I've tried to figure out the characteristics of the TOS, BIOS and XBIOS calls as far as re-entrancy is conceirned and I came to the following conclusions (correct me if I'm wrong, I've just disassembled some code): 1) TOS calls are not re-entrant whatsoever. This is due to the fact that the current registers are saved on the basepage of the current process, and restored on exit from the call. Any TOS call from within a TOS call would overwrite the saved registers. Also the stack pointer is set to point to a definite area (except in the case of the Super() call). 2) BIOS and XBIOS calls (they have the same characteristics) ARE in fact re-entrant, be it not multitasking re-entrant. The registers D3-D7 and A3-A7 are saved on a separate stack pointed to by SAVPTR ($4A2). This pointer is updated when the registers have been saved, and also when they have been restored (so you may see SAVPTR as a kind of stack pointer). The problem with this scheme is that the BIOS (XBIOS) call can get interrupted when the registers are being stored and SAVPTR is not yet updated. When the interrupt routine now uses BIOS it gets the old SAVPTR and will overwrite the registers on that stack. A better approach for the save area would have been to FIRST update SAVPTR (thereby claiming the area) and THEN save the registers. 3) It is - More or Less - possible to use (X)BIOS even from within interrupt code. After some trying it worked (it was in fact your article that stimulated me). So first the More (I omitted a test to prevent re-entrance of this routine, in this case necessary but it could be done more general, permitting re-entrance): #include <portab.h> #define SAVPTR (*(WORD **)0x4A2) static WORD savebuf[24]; /* large enough for a PC, a SR and 10 regs */ intrupt() /* e.g. a vertical blank interrupt routine */ { WORD *savep; savep = SAVPTR; /* save the pointer */ SAVPTR = savebuf + sizeof(savebuf); /* point to tail of buffer */ /* here your code using (X)BIOS calls */ SAVPTR = savep; /* restore the pointer */ } And now the Less: Because the code of the BIOS/XBIOS depends rather heavy on static/external data you can get into trouble. For instance if your interrupt routine uses Bconout(2,..) and your application uses Bconout(2,..) you will get a mess (unless you are able to restore all the global/static data altered). In the case of Midiws() it is unlikely that your program uses that XBIOS call synchronous and asynchronous; and it is unlikely (but not inconceivable) that Midiws() shares updatable data with other calls (didn't check this one). The Midi user should give it a try, I think, before reinventing the wheel. But beware of stack sizes: don't overdo it with local variables, or use a separate stack area. There could be less space on the (supervisor) stack than you think; the reason why it didn't work the first time in my case. Leo.