[comp.sys.mac.programmer] MIDI Manager/Think C/A5 Register

james_kent@CIS.OHIO-STATE.EDU (04/12/90)

I've been trying to use MIDI manager with Think C and have come across the
following problem (at least as I understand it).

MIDI manager uses interrupt routines to perform some types of tasks.  When
the interrupt routine is called, the A5 register does not necessarily contain
the application's A5 value.  A5 is used to point to an application's global
variables.  

I need a method of doing the following, using Think C :

1) save the application's A5 value somewhere when the application starts
        (Location X)
2) when the interrupt routine is called, save the current A5 value (Location Y)
    and move the value from Location X into A5
3) when the interrupt routine completes, move the value from Location Y back
    into A5 before returning

The problem is Location X can not be a global variable, since the interrupt
routine cannot access the global variables until A5 has been properly set.

I'd appreciate any code and/or comments about my understanding of this
problem.  Any pointers to Apple guidelines for methods of doing such
a thing would also be appreciated.

thanks
Jim Kent
(kent@cis.ohio-state.edu)

dan@lclark.UUCP (Dan Revel) (04/14/90)

In article <9004121500.AA00697@canoe.cis.ohio-state.edu> james_kent@CIS.OHIO-STATE.EDU writes:
>I've been trying to use MIDI manager with Think C and have come across the
>following problem (at least as I understand it).
...
>I need a method of doing the following, using Think C :
>
>1) save the application's A5 value somewhere when the application starts
>        (Location X)
>2) when the interrupt routine is called, save the current A5 value (Location Y)
>    and move the value from Location X into A5
>3) when the interrupt routine completes, move the value from Location Y back
>    into A5 before returning

Your call-back routine should be of the form:

PROCEDURE MyCallBack(chan: SndChannelPtr; cmd: SndCommand);

[IM V-480] in C that would be:

pascal void MyCallBack(SndChannelPtr chan, SndCommand cmd);

Store your CurrentA5 either in the userInfo field of your SndChannel or
else put it just before your SndChannel and use Think C's assembler to
recover it, e.g.:

Ptr		savedA5;
SndChannel	myChannel;

mySetUp()
{
	/* what have you */

	savedA5 = CurrentA5;
}

pascal void MyCallBack(SndChannelPtr chan, SndCommand cmd)
{
	Ptr	myA5, oldA5;

	asm {
		move.l	-4(chan), myA5	; get savedA5
	}
	oldA5 = SetA5(myA5);

	/* do your stuff */

	SetA5(oldA5);	/* restore A5 for the interrupt when you are done */
}

pascal long SetA5(long newA5) = { 0x2f4d, 0x0004, 0x2a5f };

SetA5 is described in Tech Note #208 as 'The New, Totally Cool Way' to
do this instead of using SetupA5() and RestoreA5().

Tech Note #180 might also be of interest to you.

That's how you do it...  I don't make any promises about the accuracy
of my code, it is untested, I just wrote it as an example...

Good Luck.
-- 
dan@lclark
tektronix!reed!lclark!dan			Dylsexics untie! (-|

cbm@well.sf.ca.us (Chris Muir) (04/15/90)

In message <9004121500.AA00697@canoe.cis.ohio-state.edu>,
james_kent@CIS.OHIO-STATE.EDU writes:
>I need a method of doing the following, using Think C :
>
>1) save the application's A5 value somewhere when the application starts
>        (Location X)
>2) when the interrupt routine is called, save the current A5 value (Location Y)
>    and move the value from Location X into A5
>3) when the interrupt routine completes, move the value from Location Y back
>    into A5 before returning


This is a little cryptic, but:

/* From OSUtil.h */
/*  access A5 from interrupt level (new way)  */
pascal long SetCurrentA5(void) = { 0x2E8D, 0x2A78, 0x0904 }; 
/* MOVE.L     A5,(A7)   	;2E8D */
/* MOVEA.L    CurrentA5,A5	;2A78 0904  */

pascal long SetA5(long) = { 0x2F4D, 0x0004, 0x2A5F }; 
/* MOVE.L     A5,$0004(A7)	;2F4D 0004 */
/* MOVEA.L    (A7)+,A5		;2A5F */


/* in your MIDI setup routine  */
	myMidiInputParams.refCon = SetCurrentA5();	
        /* stash the real A5 in refcon */


/* in your read hook (which gets passed the refcon) */
 long	oldA5;

	oldA5 = SetA5(myRefCon);			/* set A5 to "my" A5 */
	/* do stuff that needs globals */
	oldA5 = SetA5(oldA5);				/* set A5 to old A5 */



-- 
__________________________________________________________________________
Chris Muir                              |   "There is no language in our
cbm@well.sf.ca.us                       |    lungs to tell the world just
{hplabs,pacbell,ucbvax,apple}!well!cbm  |    how we feel"  - A. Partridge