Code Search for Developers
 
 
  

RedShedThreadContext.c from redshed at Krugle


Show RedShedThreadContext.c syntax highlighted

/****************************************************************************************
	RedShedThreadContext.cp $Revision: 1.2 $
		<http://rentzsch.com/redshedthreads>
	
	Copyright © 1998-2002 Red Shed Software. All rights reserved.
	by Jonathan 'Wolf' Rentzsch (jon at redshed dot net)
	
	************************************************************************************/

#include	"RedShedThreadContext.h"
#include	"require.h"
#include	"Align.h"

#define		cookieRegister68K	d7
#define		cookieRegisterPPC	r20

/**************************
*	
*	Funky Protos
*	
**************************/
#pragma mark	(Funky Protos)

	pascal
	long
SaveRedShedThreadContext68K(
	RedShedThreadContext* );

	pascal
	long
SaveRedShedThreadContext68881(
	RedShedThreadContext* );

	pascal
	long
SaveRedShedThreadContextPPC(
	RedShedThreadContext* );

	pascal
	long
SaveRedShedThreadContextPPCFP(
	RedShedThreadContext* );

	pascal
	long
SaveRedShedThreadContextAltiVec(
	RedShedThreadContext* );

	pascal
	long
SaveRedShedThreadContextAltiVecFP(
	RedShedThreadContext* );

	pascal
	void
ResumeRedShedThreadContext68K(
	RedShedThreadContext* );

	pascal
	void
ResumeRedShedThreadContext68881(
	RedShedThreadContext* );

	pascal
	void
ResumeRedShedThreadContextPPC(
	RedShedThreadContext* );

	pascal
	void
ResumeRedShedThreadContextPPCFP(
	RedShedThreadContext* );

	pascal
	void
ResumeRedShedThreadContextAltiVec(
	RedShedThreadContext* );

	pascal
	void
ResumeRedShedThreadContextAltiVecFP(
	RedShedThreadContext* );

/****************************************************************************************
*	
*	Functions
*	
****************************************************************************************/
#pragma mark	-
#pragma mark	(Functions)

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Tue, Feb 16, 1999	Created.
	wolf		Thu, Aug 26, 1999	Err. It seems if a compiler can generate AltiVec
									code, it will define __ALTIVEC_ whether or not it is
									actually generating AltiVec code. The way to tell if
									the compiler is currently generating AltiVec code
									is to test for __VEC__.
	wolf		Sat, Aug 5, 2000	Version 2. Rewrote, now takes a
									RedShedThreadContextID instead of a
									RedShedThreadContextFlags.
	
	************************************************************************************/

	pascal
	unsigned long
GetRedShedThreadContextSize(
	RedShedThreadContextID	id )
{
	unsigned long	result = 0;
	
	switch( id ) {
		case kRedShedThreadContext68K:
			result = sizeof( RedShedThreadContext68K );
			break;
		case kRedShedThreadContext68881:
			result = sizeof( RedShedThreadContext68881 );
			break;
		case kRedShedThreadContextPPC:
			result = sizeof( RedShedThreadContextPPC );
			break;
		case kRedShedThreadContextPPCFP:
			result = sizeof( RedShedThreadContextPPCFP );
			break;
		case kRedShedThreadContextAltiVec:
			result = sizeof( RedShedThreadContextAltiVec );
			break;
		case kRedShedThreadContextAltiVecFP:
			result = sizeof( RedShedThreadContextAltiVecFP );
			break;
		default:
			RequireSwitch( id );
	}
	
	return( result );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Sat, Aug 5, 2000	Created for Version 2.
	
	************************************************************************************/

	pascal
	void
InitRedShedThreadContext(
	RedShedThreadContext	*context,
	RedShedThreadContextID	id )
{
	RequirePtrAlign( context, kRedShedThreadContextAlignment );
	
	switch( id ) {
		case kRedShedThreadContext68K:
			context->saver = SaveRedShedThreadContext68K;
			context->resumer = ResumeRedShedThreadContext68K;
			break;
		case kRedShedThreadContext68881:
			context->saver = SaveRedShedThreadContext68881;
			context->resumer = ResumeRedShedThreadContext68881;
			break;
		case kRedShedThreadContextPPC:
			context->saver = SaveRedShedThreadContextPPC;
			context->resumer = ResumeRedShedThreadContextPPC;
			break;
		case kRedShedThreadContextPPCFP:
			context->saver = SaveRedShedThreadContextPPCFP;
			context->resumer = ResumeRedShedThreadContextPPCFP;
			break;
		case kRedShedThreadContextAltiVec:
			context->saver = SaveRedShedThreadContextAltiVec;
			context->resumer = ResumeRedShedThreadContextAltiVec;
			break;
		case kRedShedThreadContextAltiVecFP:
			context->saver = SaveRedShedThreadContextAltiVecFP;
			context->resumer = ResumeRedShedThreadContextAltiVec;
			break;
		default:
			RequireSwitch( id );
	}
	
	context->id = id;
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Jan 3, 2000	Created.
	wolf		Wed, Apr 5, 2000	Now uses cookieRegister instead of lastDataRegister.
	wolf		Sat, Aug 5, 2000	Version 2. Rewrote.
	wolf		Tue, Aug 8, 2000	Added two requirements.
	
	************************************************************************************/

	pascal
	void
SetRedShedThreadContextStack(
	RedShedThreadContext	*context,
	void					*stack,
	long					cookie )
{
	RedShedThreadContext68K	*context68K = (RedShedThreadContext68K*) context;
	RedShedThreadContextPPC	*contextPPC = (RedShedThreadContextPPC*) context;
	
	RequireRedShedThreadContext( context );
	RequirePtrAlign( stack, kRedShedThreadStackAlignment );
	
	switch( context->id ) {
		case kRedShedThreadContext68K:
		case kRedShedThreadContext68881: {
			long	*a6 = (long*) stack;
			a6 -= 28;
			context68K->a6 = (long) a6;
			context68K->sp = (long) a6 - 12;
			*a6-- = context68K->sp;	//	[(a6)]		stack pointer
			*a6-- = 0x00000000;		//	[-4(a6)]	Reserved CFM slot 1
			*a6-- = 0x00000000;		//	[-8(a6)]	CFM's caller address.
			*a6 = context68K->a5;	//	[-12(a6)]	CW restores a5 from here.
			context68K->cookieRegister68K = cookie;
			} break;
		case kRedShedThreadContextPPC:
		case kRedShedThreadContextPPCFP:
		case kRedShedThreadContextAltiVec:
		case kRedShedThreadContextAltiVecFP:
			contextPPC->sp = (long) stack;
			contextPPC->sp -= 32;
			contextPPC->cookieRegisterPPC = cookie;
			break;
		default:
			RequireSwitch( context->id );
	}
	
	RequireRedShedThreadContext( context );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Thu, Sep 30, 1999	Created.
	wolf		Fri, Jan 7, 2000	Renamed from LoadLastDataRegister() to
									GetRedShedThreadContextCookie(). 
	wolf		Wed, Apr 5, 2000	Now uses cookieRegister instead of lastDataRegister.
	wolf		Sat, Aug 5, 2000	Version 2, now uses the newly private
									cookieRegister68K and cookieRegisterPPC.
	
	************************************************************************************/

	asm
	pascal
	long
GetRedShedThreadContextCookie()
{
#if	powerc
	nofralloc
	mr	r3, cookieRegisterPPC
	blr
#else
	#if	GENERATINGCFM
		move.l	cookieRegister68K, d0
		rts
	#else
		movea.l	(sp)+, a0
		move.l	cookieRegister68K, (sp)
		jmp		(a0)
	#endif
#endif
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Sat, Aug 5, 2000	Created for Version 2.
	
	************************************************************************************/

	Boolean
IsValidRedShedThreadContextID(
	RedShedThreadContextID	id )
{
	switch( id ) {
		case kRedShedThreadContext68K:
		case kRedShedThreadContext68881:
		case kRedShedThreadContextPPC:
		case kRedShedThreadContextPPCFP:
		case kRedShedThreadContextAltiVec:
		case kRedShedThreadContextAltiVecFP:
			return( true );
			break;
		default:
			return( false );
	}
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Sat, Aug 5, 2000	Created for Version 2.
	
	************************************************************************************/

	ValidRedShedThreadContextCode
IsValidRedShedThreadContext(
	RedShedThreadContext	*context,
	unsigned long			size )
{
	if( context == nil )
		return( kRedShedThreadContextNil );
	
	if( !IsAligned( context, kRedShedThreadContextAlignment ) )
		return( kRedShedThreadContextNotAligned );
	
	if( !IsValidRedShedThreadContextID( context->id ) )
		return( kRedShedThreadContextInvalidID );
	
	switch( context->id ) {
		case kRedShedThreadContext68K:
			if( context->saver != SaveRedShedThreadContext68K )
				return( kRedShedThreadContextInvalidResumer );
			
			if( context->resumer != ResumeRedShedThreadContext68K )
				return( kRedShedThreadContextInvalidResumer );
			
			if( size && size != sizeof( RedShedThreadContext68K ) )
				return( kRedShedThreadContextWrongSize );
			
			if( ((RedShedThreadContext68K*) context)->sp == nil )
				return( kRedShedThreadContextStackIsNil );
			
			if( !IsAligned( (void*) ((RedShedThreadContext68K*) context)->sp, kRedShedThreadStackAlignment ) )
				return( kRedShedThreadContextStackNotAligned );
			break;
		case kRedShedThreadContext68881:
			if( context->saver != SaveRedShedThreadContext68881 )
				return( kRedShedThreadContextInvalidResumer );
			
			if( context->resumer != ResumeRedShedThreadContext68881 )
				return( kRedShedThreadContextInvalidResumer );
			
			if( size && size != sizeof( RedShedThreadContext68881 ) )
				return( kRedShedThreadContextWrongSize );
			
			if( ((RedShedThreadContext68881*) context)->sp == nil )
				return( kRedShedThreadContextStackIsNil );
			
			if( !IsAligned( (void*) ((RedShedThreadContext68881*) context)->sp, kRedShedThreadStackAlignment ) )
				return( kRedShedThreadContextStackNotAligned );
			break;
		case kRedShedThreadContextPPC:
			if( context->saver != SaveRedShedThreadContextPPC )
				return( kRedShedThreadContextInvalidResumer );
			
			if( context->resumer != ResumeRedShedThreadContextPPC )
				return( kRedShedThreadContextInvalidResumer );
			
			if( size && size != sizeof( RedShedThreadContextPPC ) )
				return( kRedShedThreadContextWrongSize );
			
			if( ((RedShedThreadContextPPC*) context)->sp == nil )
				return( kRedShedThreadContextStackIsNil );
			
			if( !IsAligned( (void*) ((RedShedThreadContextPPC*) context)->sp, kRedShedThreadStackAlignment ) )
				return( kRedShedThreadContextStackNotAligned );
			break;
		case kRedShedThreadContextPPCFP:
			if( context->saver != SaveRedShedThreadContextPPCFP )
				return( kRedShedThreadContextInvalidResumer );
			
			if( context->resumer != ResumeRedShedThreadContextPPCFP )
				return( kRedShedThreadContextInvalidResumer );
			
			if( size && size != sizeof( RedShedThreadContextPPCFP ) )
				return( kRedShedThreadContextWrongSize );
			
			if( ((RedShedThreadContextPPCFP*) context)->sp == nil )
				return( kRedShedThreadContextStackIsNil );
			
			if( !IsAligned( (void*) ((RedShedThreadContextPPCFP*) context)->sp, kRedShedThreadStackAlignment ) )
				return( kRedShedThreadContextStackNotAligned );
			break;
		case kRedShedThreadContextAltiVec:
			if( context->saver != SaveRedShedThreadContextAltiVec )
				return( kRedShedThreadContextInvalidResumer );
			
			if( context->resumer != ResumeRedShedThreadContextAltiVec )
				return( kRedShedThreadContextInvalidResumer );
			
			if( size && size != sizeof( RedShedThreadContextAltiVec ) )
				return( kRedShedThreadContextWrongSize );
			
			if( ((RedShedThreadContextAltiVec*) context)->sp == nil )
				return( kRedShedThreadContextStackIsNil );
			
			if( !IsAligned( (void*) ((RedShedThreadContextAltiVec*) context)->sp, kRedShedThreadStackAlignment ) )
				return( kRedShedThreadContextStackNotAligned );
			break;
		case kRedShedThreadContextAltiVecFP:
			if( context->saver != SaveRedShedThreadContextAltiVecFP )
				return( kRedShedThreadContextInvalidResumer );
			
			if( context->resumer != ResumeRedShedThreadContextAltiVecFP )
				return( kRedShedThreadContextInvalidResumer );
			
			if( size && size != sizeof( RedShedThreadContextAltiVecFP ) )
				return( kRedShedThreadContextWrongSize );
			
			if( ((RedShedThreadContextAltiVecFP*) context)->sp == nil )
				return( kRedShedThreadContextStackIsNil );
			
			if( !IsAligned( (void*) ((RedShedThreadContextAltiVecFP*) context)->sp, kRedShedThreadStackAlignment ) )
				return( kRedShedThreadContextStackNotAligned );
			break;
			break;
		default:
			RequireSwitch( context->id );
	}
	
	return( kRedShedThreadContextValid );
}

#pragma mark	-
#pragma mark	(Parameter Passing Conventions and Register Preservation)
/****************************************************************************************
	Parameter Passing Conventions and Register Preservation
	
	Classic 68K
		Classic 68K doesn't define a standard parameter passing convention, so we use the
		Pascal calling convention. We use the 'pascal' keyword so the compiler generates
		code that uses the Pascal calling convention.
		
		The Pascal calling convention requires the caller make space for the callee's
		result (if any) and all parameters. The parameters are pushed from left to right,
		followed by the return address. The callee is responsible for popping all
		parameters before returning to the caller. The function result (if any) is left
		on the stack.
		
		The Pascal calling convention doesn't explicitly state what registers should be
		saved, so we use the rather Draconian CFM-68K register preservation guidelines,
		which requires we preserve registers d3-d7, a2-a7 and fp4-fp7. That leaves us
		with d0-d2, a0-a1 and fp0-fp3 for our use.
	
	CFM-68K
		CFM-68K defines a standard parameter passing convention, so the 'pascal' keyword
		(required when generating Classic 68K code) is ignored.
		
		Under CFM-68K, parameters are pushed from right to left onto the stack, followed
		by the return address. The function's result (if any) is returned in register D0.
		CFM-68K requires we preserve registers d3-d7, a2-a7 and fp4-fp7. That leaves us
		with d0-d2, a0-a1 and fp0-fp3 for our use.
	
	PowerPC
		The smart folks at IBM actually took time out of their busy days and defined a
		STANDARD PARAMETER PASSING CONVENTION for ALL PowerPCs, REGARDLESS of the
		OPERATING SYSTEM or LANGUAGE. Whew. Thanks guys.
		
		This is a good thing for all involved, including processor designers, compiler
		writers, debugger geeks and operating system nerds.
		
		Since IBM went through all the trouble to define the parameter passing
		convention, Apple simply took IBM's definition and whacked it with a big ol'
		rubber stamp. Wha-la, we have CFM-PPC.
		
		PowerPC code always uses CFM parameter passing conventions, so the 'pascal'
		keyword (required when generating Classic 68K code) is ignored.
		
		Under PowerPC, parameters are passed in registers left to right, starting with
		register r3. The function's result (if any) is stored in register r3.
		
		The PowerPC runtime architecture is well-defined and requires we preserve
		registers r1-r2, r13-r31, fp14-fp31, and a chunk of CR (CR[2], CR[3] and CR[4]
		to be precise). That leaves us with r0, r3-r12 and fp0-fp13.
	
	************************************************************************************/
#pragma mark	(Registers Thrashed per RedShedThreadContextID)
/****************************************************************************************
	Registers Thrashed per RedShedThreadContextID
	
	Here, thrash is defined as "save and restore".
	
	kRedShedThreadContext68K
		We thrash 68K registers pc, sp, d3-d7 and a1-a7.
	
	kRedShedThreadContext68881
		We thrash 68K registers pc, sp, d3-d7, a1-a7 and 68881 registers fp4-fp7.

	kRedShedThreadContextPPC
		We thrash PowerPC registers pc, sp, cr, toc, r13-r31, fp14-fp31 and fpscr.
		
	kRedShedThreadContextPPCFP
		We thrash PowerPC registers pc, sp, cr, toc, r13-r31, fp0-fp31 and fpscr.
		                                                      ^^^^^^^^
		As documented in Technote 1158, _Levatatus Interruptus_, the PowerPC interrupt
		handler saves and restores nonvolatile floating point registers (fp14-fp31) but
		not the volatile registers (fp0-fp13). THIS IS A BUG.
		
		This behavior results in a tragic situation. If one of your threads uses the
		volatile floating point registers, and was called from an interrupt-time
		callback (like a VBL task, Time Manager, Deferred Task, File Manager
		completion routine or Open Transport notifier), you will stomp on the
		interrupted task's registers.
		
		Within a few milliseconds, you will be very unhappy. Perhaps Excel turns out
		wrong numbers, or maybe your game blits garbage to the screen. In any scenario,
		it's not good.
		
		The work-around is to save and restore the volatile floating point registers
		if your thread if going to use them. Well, it just so happens that
		RedShedThreadContext was busy saving and restoring the nonvolatile floating
		point registers for you. It would be happy to save and restore the volatile
		registers at the same time. You take a performance hit, though, since EVERY
		8 BYTE REGISTER IS LOADED AND STORED FOR EACH CONTEXT SWITCH.
		
		Executive Summary: Either don't do floating point math in a thread, or don't
		call such a thread at interrupt time or use kRedShedThreadContextPPCFP and
		be blissfully unaware but suffer the overhead.
	
	kRedShedThreadContextAltiVec
		We thrash PowerPC registers pc, sp, cr, toc, r13-r31, fp14-fp31, fpscr,
		vrsave and vscr.
		
		In addition, we read the vrsave register and thrash whatever vector registers
		are marked "in use".
	
	kRedShedThreadContextAltiVecFP
		We thrash PowerPC registers pc, sp, cr, toc, r13-r31, fp0-fp31, fpscr,
		vrsave and vscr.
		
		In addition, we read the vrsave register and thrash whatever vector registers
		are marked "in use".
		
		This is a hybrid between the kRedShedThreadContextAltiVec and
		kRedShedThreadContextPPCFP context IDs. I'm tired of typing, go read the
		description for kRedShedThreadContextPPCFP.
	
	************************************************************************************/

/****************************************************************************************
*	
*	Save Functions
*	
****************************************************************************************/
#pragma mark	-
#pragma mark	(Save Functions)

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Sat, Aug 5, 2000	Created.
	wolf		Tue, Aug 8, 2000	Moved the call to RequireRedShedThreadContext after
									the call to the context's saver and added a few
									requirements before the call to the saver.
	
	************************************************************************************/

	pascal
	long
SaveRedShedThreadContext(
	RedShedThreadContext	*context )
{
	long	result;
	
	//	We can't call RequireRedShedThreadContext yet since its stack
	//	hasn't been set yet, so we run a few tests here before we call
	//	the context's saver.
	RequireSupport( ValidRedShedThreadContextCode code = IsValidRedShedThreadContext( context, 0 ) );
	Require( code == kRedShedThreadContextValid
			|| code == kRedShedThreadContextStackIsNil
			|| code == kRedShedThreadContextStackNotAligned );
	RequirePtrAlign( context, kRedShedThreadContextAlignment );
	RequireRedShedThreadContextID( context->id );
	RequireProcPtr( context->saver );
	RequireProcPtr( context->resumer );
	
	//	Call the saver.
	result = context->saver( context );
	
	//	Now that the context is full of supposedly valid values, we can finally
	//	call RequireRedShedThreadContext.
	//RequireRedShedThreadContext( context );
	
	return( result );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Jun 1, 1998	Created as SaveRedShedThreadContext.
	wolf		Thu, Nov 19, 1998	Rolled in PowerPC code.
	wolf		Tue, Feb 16, 1999	In preparing for AltiVec, I rewrote the code
									to use the off( FIELD ) macro instead of hard-coded
									offsets.
	wolf		Thu, Aug 26, 1999	Rewrote, throwing out all optimizations.
									However, the code is smaller, easier to understand
									and I added AltiVec support.
									Once I'm sure it all works, I'll optimize it again.
	wolf		Fri, Feb 11, 2000	Added nofralloc assembler directive to PowerPC side.
									This stops CodeWarrior from generating automatic
									register save/restore functions.
	wolf		Sat, Aug 5, 2000	Broke from monolithic compile-time and run-time
									conditional SaveRedShedThreadContext into dedicated
									function.
	
	************************************************************************************/
	
	asm
	pascal
	long
SaveRedShedThreadContext68K(
	RedShedThreadContext* )
{
#if	!powerc
#define	off( FIELD )	struct(RedShedThreadContext68K.FIELD)
	//	68K
	move.l		(sp)+, d2					//	Pop the rtn address.
	movea.l		(sp)+, a0					//	Pop the address to the context structure.
	movem.l		d2-d7/a1-a7, off(pc)(a0)	//	Save the registers into the context structure.
	#if	GENERATINGCFM
		moveq.l		#1, d0					//	Return true in register d0.
	#else
		move.l		#1, (sp)				//	Return true on the stack.
	#endif
	movea.l		d2, a0
	jmp			(a0)						//	We're outta here.
#undef	off
#endif
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Jun 1, 1998	Created as SaveRedShedThreadContext.
	wolf		Thu, Nov 19, 1998	Rolled in PowerPC code.
	wolf		Tue, Feb 16, 1999	In preparing for AltiVec, I rewrote the code
									to use the off( FIELD ) macro instead of hard-coded
									offsets.
	wolf		Thu, Aug 26, 1999	Rewrote, throwing out all optimizations.
									However, the code is smaller, easier to understand
									and I added AltiVec support.
									Once I'm sure it all works, I'll optimize it again.
	wolf		Fri, Feb 11, 2000	Added nofralloc assembler directive to PowerPC side.
									This stops CodeWarrior from generating automatic
									register save/restore functions.
	wolf		Sat, Aug 5, 2000	Broke from monolithic compile-time and run-time
									conditional SaveRedShedThreadContext into dedicated
									function.
	
	************************************************************************************/

	asm
	pascal
	long
SaveRedShedThreadContext68881(
	RedShedThreadContext* )
{
#if	!powerc
#define	off( FIELD )	struct(RedShedThreadContext68881.FIELD)
	//	68K
	move.l		(sp)+, d2					//	Pop the rtn address.
	movea.l		(sp)+, a0					//	Pop the address to the context structure.
	movem.l		d2-d7/a1-a7, off(pc)(a0)	//	Save the registers into the context structure.
	//	68K Floating Point
	adda.l		#off(fp4), a0				//	Advance the pointer to the fp registers.
	opword		0xF210, 0xF00F				//	CWPro2 spits up on floating point 68K code.
	//fmovem.l	fp4-fp7, (a0)				//	Save the floating point registers.
	#if	GENERATINGCFM
		moveq.l		#1, d0					//	Return true in register d0.
	#else
		move.l		#1, (sp)				//	Return true on the stack.
	#endif
	movea.l		d2, a0
	jmp			(a0)						//	We're outta here.
#undef	off
#endif
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Jun 1, 1998	Created as SaveRedShedThreadContext.
	wolf		Thu, Nov 19, 1998	Rolled in PowerPC code.
	wolf		Tue, Feb 16, 1999	In preparing for AltiVec, I rewrote the code
									to use the off( FIELD ) macro instead of hard-coded
									offsets.
	wolf		Thu, Aug 26, 1999	Rewrote, throwing out all optimizations.
									However, the code is smaller, easier to understand
									and I added AltiVec support.
									Once I'm sure it all works, I'll optimize it again.
	wolf		Fri, Feb 11, 2000	Added nofralloc assembler directive to PowerPC side.
									This stops CodeWarrior from generating automatic
									register save/restore functions.
	wolf		Sat, Aug 5, 2000	Broke from monolithic compile-time and run-time
									conditional SaveRedShedThreadContext into dedicated
									function.
	
	************************************************************************************/

	asm
	pascal
	long
SaveRedShedThreadContextPPC(
	RedShedThreadContext* )
{
#if	powerc
#define	off( FIELD )	RedShedThreadContextPPC.FIELD
	//	PowerPC
	nofralloc
	mflr	r4					//	Load return address.
	stw		r4, off(pc)(r3)		//	Store return address into program counter.
	mfcr	r5					//	Load condition register.
	stw		r5, off(cr)(r3)		//	Store condition register.
	stw		r1, off(sp)(r3)		//	Store stack pointer.
	stw		r2, off(toc)(r3)	//	Store table of contents.
	stw		r13, off(r13)(r3)	//	Store r13 thru r31...
	stw		r14, off(r14)(r3)
	stw		r15, off(r15)(r3)
	stw		r16, off(r16)(r3)
	stw		r17, off(r17)(r3)
	stw		r18, off(r18)(r3)
	stw		r19, off(r19)(r3)
	stw		r20, off(r20)(r3)
	stw		r21, off(r21)(r3)
	stw		r22, off(r22)(r3)
	stw		r23, off(r23)(r3)
	stw		r24, off(r24)(r3)
	stw		r25, off(r25)(r3)
	stw		r26, off(r26)(r3)
	stw		r27, off(r27)(r3)
	stw		r28, off(r28)(r3)
	stw		r29, off(r29)(r3)
	stw		r30, off(r30)(r3)
	stw		r31, off(r31)(r3)
	//	PowerPC Floating Point
	stfd	fp14, off(fp14)(r3)	//	Save fp14 thru fp31...
	stfd	fp15, off(fp15)(r3)
	stfd	fp16, off(fp16)(r3)
	stfd	fp17, off(fp17)(r3)
	stfd	fp18, off(fp18)(r3)
	stfd	fp19, off(fp19)(r3)
	stfd	fp20, off(fp20)(r3)
	stfd	fp21, off(fp21)(r3)
	stfd	fp22, off(fp22)(r3)
	stfd	fp23, off(fp23)(r3)
	stfd	fp24, off(fp24)(r3)
	stfd	fp25, off(fp25)(r3)
	stfd	fp26, off(fp26)(r3)
	stfd	fp27, off(fp27)(r3)
	stfd	fp28, off(fp28)(r3)
	stfd	fp29, off(fp29)(r3)
	stfd	fp30, off(fp30)(r3)
	stfd	fp31, off(fp31)(r3)
	mffs	fp0					//	Load floating point status and control register.
	stfd	fp0, off(fpscr)(r3)	//	Store floating point status and control register.
	li		r3, 1				//	Return true.
	blr							//	We're outta here.
#undef	off
#endif
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Jun 1, 1998	Created as SaveRedShedThreadContext.
	wolf		Thu, Nov 19, 1998	Rolled in PowerPC code.
	wolf		Tue, Feb 16, 1999	In preparing for AltiVec, I rewrote the code
									to use the off( FIELD ) macro instead of hard-coded
									offsets.
	wolf		Thu, Aug 26, 1999	Rewrote, throwing out all optimizations.
									However, the code is smaller, easier to understand
									and I added AltiVec support.
									Once I'm sure it all works, I'll optimize it again.
	wolf		Fri, Feb 11, 2000	Added nofralloc assembler directive to PowerPC side.
									This stops CodeWarrior from generating automatic
									register save/restore functions.
	wolf		Sat, Aug 5, 2000	Broke from monolithic compile-time and run-time
									conditional SaveRedShedThreadContext into dedicated
									function.
	
	************************************************************************************/

	asm
	pascal
	long
SaveRedShedThreadContextPPCFP(
	RedShedThreadContext* )
{
#if	powerc
#define	off( FIELD )	RedShedThreadContextPPCFP.FIELD
	//	PowerPC
	nofralloc
	mflr	r4					//	Load return address.
	stw		r4, off(pc)(r3)		//	Store return address into program counter.
	mfcr	r5					//	Load condition register.
	stw		r5, off(cr)(r3)		//	Store condition register.
	stw		r1, off(sp)(r3)		//	Store stack pointer.
	stw		r2, off(toc)(r3)	//	Store table of contents.
	stw		r13, off(r13)(r3)	//	Store r13 thru r31...
	stw		r14, off(r14)(r3)
	stw		r15, off(r15)(r3)
	stw		r16, off(r16)(r3)
	stw		r17, off(r17)(r3)
	stw		r18, off(r18)(r3)
	stw		r19, off(r19)(r3)
	stw		r20, off(r20)(r3)
	stw		r21, off(r21)(r3)
	stw		r22, off(r22)(r3)
	stw		r23, off(r23)(r3)
	stw		r24, off(r24)(r3)
	stw		r25, off(r25)(r3)
	stw		r26, off(r26)(r3)
	stw		r27, off(r27)(r3)
	stw		r28, off(r28)(r3)
	stw		r29, off(r29)(r3)
	stw		r30, off(r30)(r3)
	stw		r31, off(r31)(r3)
	//	PowerPC Floating Point
	stfd	fp0, off(fp0)(r3)	//	Save fp0 thru fp31...
	stfd	fp1, off(fp1)(r3)
	stfd	fp2, off(fp2)(r3)
	stfd	fp3, off(fp3)(r3)
	stfd	fp4, off(fp4)(r3)
	stfd	fp5, off(fp5)(r3)
	stfd	fp6, off(fp6)(r3)
	stfd	fp7, off(fp7)(r3)
	stfd	fp8, off(fp8)(r3)
	stfd	fp9, off(fp9)(r3)
	stfd	fp10, off(fp10)(r3)
	stfd	fp11, off(fp11)(r3)
	stfd	fp12, off(fp12)(r3)
	stfd	fp13, off(fp13)(r3)
	stfd	fp14, off(fp14)(r3)
	stfd	fp15, off(fp15)(r3)
	stfd	fp16, off(fp16)(r3)
	stfd	fp17, off(fp17)(r3)
	stfd	fp18, off(fp18)(r3)
	stfd	fp19, off(fp19)(r3)
	stfd	fp20, off(fp20)(r3)
	stfd	fp21, off(fp21)(r3)
	stfd	fp22, off(fp22)(r3)
	stfd	fp23, off(fp23)(r3)
	stfd	fp24, off(fp24)(r3)
	stfd	fp25, off(fp25)(r3)
	stfd	fp26, off(fp26)(r3)
	stfd	fp27, off(fp27)(r3)
	stfd	fp28, off(fp28)(r3)
	stfd	fp29, off(fp29)(r3)
	stfd	fp30, off(fp30)(r3)
	stfd	fp31, off(fp31)(r3)
	mffs	fp0					//	Load floating point status and control register.
	stfd	fp0, off(fpscr)(r3)	//	Store floating point status and control register.
	li		r3, 1				//	Return true.
	blr							//	We're outta here.
#undef	off
#endif
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Jun 1, 1998	Created as SaveRedShedThreadContext.
	wolf		Thu, Nov 19, 1998	Rolled in PowerPC code.
	wolf		Tue, Feb 16, 1999	In preparing for AltiVec, I rewrote the code
									to use the off( FIELD ) macro instead of hard-coded
									offsets.
	wolf		Thu, Aug 26, 1999	Rewrote, throwing out all optimizations.
									However, the code is smaller, easier to understand
									and I added AltiVec support.
									Once I'm sure it all works, I'll optimize it again.
	wolf		Fri, Feb 11, 2000	Added nofralloc assembler directive to PowerPC side.
									This stops CodeWarrior from generating automatic
									register save/restore functions.
	wolf		Sat, Aug 5, 2000	Broke from monolithic compile-time and run-time
									conditional SaveRedShedThreadContext into dedicated
									function.
	
	************************************************************************************/

	asm
	pascal
	long
SaveRedShedThreadContextAltiVec(
	RedShedThreadContext* )
{
#if	powerc
#define	off( FIELD )	RedShedThreadContextAltiVec.FIELD
	//	PowerPC
	nofralloc
	mflr	r4					//	Load return address.
	stw		r4, off(pc)(r3)		//	Store return address into program counter.
	mfcr	r5					//	Load condition register.
	stw		r5, off(cr)(r3)		//	Store condition register.
	stw		r1, off(sp)(r3)		//	Store stack pointer.
	stw		r2, off(toc)(r3)	//	Store table of contents.
	stw		r13, off(r13)(r3)	//	Store r13 thru r31...
	stw		r14, off(r14)(r3)
	stw		r15, off(r15)(r3)
	stw		r16, off(r16)(r3)
	stw		r17, off(r17)(r3)
	stw		r18, off(r18)(r3)
	stw		r19, off(r19)(r3)
	stw		r20, off(r20)(r3)
	stw		r21, off(r21)(r3)
	stw		r22, off(r22)(r3)
	stw		r23, off(r23)(r3)
	stw		r24, off(r24)(r3)
	stw		r25, off(r25)(r3)
	stw		r26, off(r26)(r3)
	stw		r27, off(r27)(r3)
	stw		r28, off(r28)(r3)
	stw		r29, off(r29)(r3)
	stw		r30, off(r30)(r3)
	stw		r31, off(r31)(r3)
	//	PowerPC Floating Point
	stfd	fp14, off(fp14)(r3)	//	Save fp14 thru fp31...
	stfd	fp15, off(fp15)(r3)
	stfd	fp16, off(fp16)(r3)
	stfd	fp17, off(fp17)(r3)
	stfd	fp18, off(fp18)(r3)
	stfd	fp19, off(fp19)(r3)
	stfd	fp20, off(fp20)(r3)
	stfd	fp21, off(fp21)(r3)
	stfd	fp22, off(fp22)(r3)
	stfd	fp23, off(fp23)(r3)
	stfd	fp24, off(fp24)(r3)
	stfd	fp25, off(fp25)(r3)
	stfd	fp26, off(fp26)(r3)
	stfd	fp27, off(fp27)(r3)
	stfd	fp28, off(fp28)(r3)
	stfd	fp29, off(fp29)(r3)
	stfd	fp30, off(fp30)(r3)
	stfd	fp31, off(fp31)(r3)
	mffs	fp0					//	Load floating point status and control register.
	stfd	fp0, off(fpscr)(r3)	//	Store floating point status and control register.
	//	AltiVec
	mfspr	r6, 256				//	Load VRSave.
vr0:
	andis.	r7, r6, 0x8000
	beq		vr1
	li		r8, off( vr0 )
	stvx	vr0, r8, r3
vr1:
	andis.	r7, r6, 0x4000
	beq		vr2
	li		r8, off( vr1 )
	stvx	vr1, r8, r3
vr2:
	andis.	r7, r6, 0x2000
	beq		vr3
	li		r8, off( vr2 )
	stvx	vr2, r8, r3
vr3:
	andis.	r7, r6, 0x1000
	beq		vr4
	li		r8, off( vr3 )
	stvx	vr3, r8, r3
vr4:
	andis.	r7, r6, 0x0800
	beq		vr5
	li		r8, off( vr4 )
	stvx	vr4, r8, r3
vr5:
	andis.	r7, r6, 0x0400
	beq		vr6
	li		r8, off( vr5 )
	stvx	vr5, r8, r3
vr6:
	andis.	r7, r6, 0x0200
	beq		vr7
	li		r8, off( vr6 )
	stvx	vr6, r8, r3
vr7:
	andis.	r7, r6, 0x0100
	beq		vr8
	li		r8, off( vr7 )
	stvx	vr7, r8, r3
vr8:
	andis.	r7, r6, 0x0080
	beq		vr9
	li		r8, off( vr8 )
	stvx	vr8, r8, r3
vr9:
	andis.	r7, r6, 0x0040
	beq		vr10
	li		r8, off( vr9 )
	stvx	vr9, r8, r3
vr10:
	andis.	r7, r6, 0x0020
	beq		vr11
	li		r8, off( vr10 )
	stvx	vr10, r8, r3
vr11:
	andis.	r7, r6, 0x0010
	beq		vr12
	li		r8, off( vr11 )
	stvx	vr11, r8, r3
vr12:
	andis.	r7, r6, 0x0008
	beq		vr13
	li		r8, off( vr12 )
	stvx	vr12, r8, r3
vr13:
	andis.	r7, r6, 0x0004
	beq		vr14
	li		r8, off( vr13 )
	stvx	vr13, r8, r3
vr14:
	andis.	r7, r6, 0x0002
	beq		vr15
	li		r8, off( vr14 )
	stvx	vr14, r8, r3
vr15:
	andis.	r7, r6, 0x0001
	beq		vr16
	li		r8, off( vr15 )
	stvx	vr15, r8, r3
vr16:
	andi.	r7, r6, 0x8000
	beq		vr17
	li		r8, off( vr16 )
	stvx	vr16, r8, r3
vr17:
	andi.	r7, r6, 0x4000
	beq		vr18
	li		r8, off( vr17 )
	stvx	vr17, r8, r3
vr18:
	andi.	r7, r6, 0x2000
	beq		vr19
	li		r8, off( vr18 )
	stvx	vr18, r8, r3
vr19:
	andi.	r7, r6, 0x1000
	beq		vr20
	li		r8, off( vr19 )
	stvx	vr19, r8, r3
vr20:
	andi.	r7, r6, 0x0800
	beq		vr21
	li		r8, off( vr20 )
	stvx	vr20, r8, r3
vr21:
	andi.	r7, r6, 0x0400
	beq		vr22
	li		r8, off( vr21 )
	stvx	vr21, r8, r3
vr22:
	andi.	r7, r6, 0x0200
	beq		vr23
	li		r8, off( vr22 )
	stvx	vr22, r8, r3
vr23:
	andi.	r7, r6, 0x0100
	beq		vr24
	li		r8, off( vr23 )
	stvx	vr23, r8, r3
vr24:
	andi.	r7, r6, 0x0080
	beq		vr25
	li		r8, off( vr24 )
	stvx	vr24, r8, r3
vr25:
	andi.	r7, r6, 0x0040
	beq		vr26
	li		r8, off( vr25 )
	stvx	vr25, r8, r3
vr26:
	andi.	r7, r6, 0x0020
	beq		vr27
	li		r8, off( vr26 )
	stvx	vr26, r8, r3
vr27:
	andi.	r7, r6, 0x0010
	beq		vr28
	li		r8, off( vr27 )
	stvx	vr27, r8, r3
vr28:
	andi.	r7, r6, 0x0008
	beq		vr29
	li		r8, off( vr28 )
	stvx	vr28, r8, r3
vr29:
	andi.	r7, r6, 0x0004
	beq		vr30
	li		r8, off( vr29 )
	stvx	vr29, r8, r3
vr30:
	andi.	r7, r6, 0x0002
	beq		vr31
	li		r8, off( vr30 )
	stvx	vr30, r8, r3
vr31:
	andi.	r7, r6, 0x0001
	beq		done
	li		r8, off( vr31 )
	stvx	vr31, r8, r3
done:
	mfvscr	vr0					//	Load Vector Status and Control Register.
	li		r8, off( vscr )
	stvx	vr0, r8, r3			//	Store Vector Status and Control Register.
	
	stw		r6, off(vrsave)(r3)	//	Store VRSave.
	
	li		r3, 1				//	Return true.
	blr							//	We're outta here.
#undef	off
#endif
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Jun 1, 1998	Created as SaveRedShedThreadContext.
	wolf		Thu, Nov 19, 1998	Rolled in PowerPC code.
	wolf		Tue, Feb 16, 1999	In preparing for AltiVec, I rewrote the code
									to use the off( FIELD ) macro instead of hard-coded
									offsets.
	wolf		Thu, Aug 26, 1999	Rewrote, throwing out all optimizations.
									However, the code is smaller, easier to understand
									and I added AltiVec support.
									Once I'm sure it all works, I'll optimize it again.
	wolf		Fri, Feb 11, 2000	Added nofralloc assembler directive to PowerPC side.
									This stops CodeWarrior from generating automatic
									register save/restore functions.
	wolf		Sat, Aug 5, 2000	Broke from monolithic compile-time and run-time
									conditional SaveRedShedThreadContext into dedicated
									function.
	
	************************************************************************************/

	asm
	pascal
	long
SaveRedShedThreadContextAltiVecFP(
	RedShedThreadContext* )
{
#if	powerc
#define	off( FIELD )	RedShedThreadContextAltiVecFP.FIELD
	//	PowerPC
	nofralloc
	mflr	r4					//	Load return address.
	stw		r4, off(pc)(r3)		//	Store return address into program counter.
	mfcr	r5					//	Load condition register.
	stw		r5, off(cr)(r3)		//	Store condition register.
	stw		r1, off(sp)(r3)		//	Store stack pointer.
	stw		r2, off(toc)(r3)	//	Store table of contents.
	stw		r13, off(r13)(r3)	//	Store r13 thru r31...
	stw		r14, off(r14)(r3)
	stw		r15, off(r15)(r3)
	stw		r16, off(r16)(r3)
	stw		r17, off(r17)(r3)
	stw		r18, off(r18)(r3)
	stw		r19, off(r19)(r3)
	stw		r20, off(r20)(r3)
	stw		r21, off(r21)(r3)
	stw		r22, off(r22)(r3)
	stw		r23, off(r23)(r3)
	stw		r24, off(r24)(r3)
	stw		r25, off(r25)(r3)
	stw		r26, off(r26)(r3)
	stw		r27, off(r27)(r3)
	stw		r28, off(r28)(r3)
	stw		r29, off(r29)(r3)
	stw		r30, off(r30)(r3)
	stw		r31, off(r31)(r3)
	//	PowerPC Floating Point
	stfd	fp0, off(fp0)(r3)	//	Save fp0 thru fp31...
	stfd	fp1, off(fp1)(r3)
	stfd	fp2, off(fp2)(r3)
	stfd	fp3, off(fp3)(r3)
	stfd	fp4, off(fp4)(r3)
	stfd	fp5, off(fp5)(r3)
	stfd	fp6, off(fp6)(r3)
	stfd	fp7, off(fp7)(r3)
	stfd	fp8, off(fp8)(r3)
	stfd	fp9, off(fp9)(r3)
	stfd	fp10, off(fp10)(r3)
	stfd	fp11, off(fp11)(r3)
	stfd	fp12, off(fp12)(r3)
	stfd	fp13, off(fp13)(r3)
	stfd	fp14, off(fp14)(r3)
	stfd	fp15, off(fp15)(r3)
	stfd	fp16, off(fp16)(r3)
	stfd	fp17, off(fp17)(r3)
	stfd	fp18, off(fp18)(r3)
	stfd	fp19, off(fp19)(r3)
	stfd	fp20, off(fp20)(r3)
	stfd	fp21, off(fp21)(r3)
	stfd	fp22, off(fp22)(r3)
	stfd	fp23, off(fp23)(r3)
	stfd	fp24, off(fp24)(r3)
	stfd	fp25, off(fp25)(r3)
	stfd	fp26, off(fp26)(r3)
	stfd	fp27, off(fp27)(r3)
	stfd	fp28, off(fp28)(r3)
	stfd	fp29, off(fp29)(r3)
	stfd	fp30, off(fp30)(r3)
	stfd	fp31, off(fp31)(r3)
	mffs	fp0					//	Load floating point status and control register.
	stfd	fp0, off(fpscr)(r3)	//	Store floating point status and control register.
	//	AltiVec
	mfspr	r6, 256				//	Load VRSave.
vr0:
	andis.	r7, r6, 0x8000
	beq		vr1
	li		r8, off( vr0 )
	stvx	vr0, r8, r3
vr1:
	andis.	r7, r6, 0x4000
	beq		vr2
	li		r8, off( vr1 )
	stvx	vr1, r8, r3
vr2:
	andis.	r7, r6, 0x2000
	beq		vr3
	li		r8, off( vr2 )
	stvx	vr2, r8, r3
vr3:
	andis.	r7, r6, 0x1000
	beq		vr4
	li		r8, off( vr3 )
	stvx	vr3, r8, r3
vr4:
	andis.	r7, r6, 0x0800
	beq		vr5
	li		r8, off( vr4 )
	stvx	vr4, r8, r3
vr5:
	andis.	r7, r6, 0x0400
	beq		vr6
	li		r8, off( vr5 )
	stvx	vr5, r8, r3
vr6:
	andis.	r7, r6, 0x0200
	beq		vr7
	li		r8, off( vr6 )
	stvx	vr6, r8, r3
vr7:
	andis.	r7, r6, 0x0100
	beq		vr8
	li		r8, off( vr7 )
	stvx	vr7, r8, r3
vr8:
	andis.	r7, r6, 0x0080
	beq		vr9
	li		r8, off( vr8 )
	stvx	vr8, r8, r3
vr9:
	andis.	r7, r6, 0x0040
	beq		vr10
	li		r8, off( vr9 )
	stvx	vr9, r8, r3
vr10:
	andis.	r7, r6, 0x0020
	beq		vr11
	li		r8, off( vr10 )
	stvx	vr10, r8, r3
vr11:
	andis.	r7, r6, 0x0010
	beq		vr12
	li		r8, off( vr11 )
	stvx	vr11, r8, r3
vr12:
	andis.	r7, r6, 0x0008
	beq		vr13
	li		r8, off( vr12 )
	stvx	vr12, r8, r3
vr13:
	andis.	r7, r6, 0x0004
	beq		vr14
	li		r8, off( vr13 )
	stvx	vr13, r8, r3
vr14:
	andis.	r7, r6, 0x0002
	beq		vr15
	li		r8, off( vr14 )
	stvx	vr14, r8, r3
vr15:
	andis.	r7, r6, 0x0001
	beq		vr16
	li		r8, off( vr15 )
	stvx	vr15, r8, r3
vr16:
	andi.	r7, r6, 0x8000
	beq		vr17
	li		r8, off( vr16 )
	stvx	vr16, r8, r3
vr17:
	andi.	r7, r6, 0x4000
	beq		vr18
	li		r8, off( vr17 )
	stvx	vr17, r8, r3
vr18:
	andi.	r7, r6, 0x2000
	beq		vr19
	li		r8, off( vr18 )
	stvx	vr18, r8, r3
vr19:
	andi.	r7, r6, 0x1000
	beq		vr20
	li		r8, off( vr19 )
	stvx	vr19, r8, r3
vr20:
	andi.	r7, r6, 0x0800
	beq		vr21
	li		r8, off( vr20 )
	stvx	vr20, r8, r3
vr21:
	andi.	r7, r6, 0x0400
	beq		vr22
	li		r8, off( vr21 )
	stvx	vr21, r8, r3
vr22:
	andi.	r7, r6, 0x0200
	beq		vr23
	li		r8, off( vr22 )
	stvx	vr22, r8, r3
vr23:
	andi.	r7, r6, 0x0100
	beq		vr24
	li		r8, off( vr23 )
	stvx	vr23, r8, r3
vr24:
	andi.	r7, r6, 0x0080
	beq		vr25
	li		r8, off( vr24 )
	stvx	vr24, r8, r3
vr25:
	andi.	r7, r6, 0x0040
	beq		vr26
	li		r8, off( vr25 )
	stvx	vr25, r8, r3
vr26:
	andi.	r7, r6, 0x0020
	beq		vr27
	li		r8, off( vr26 )
	stvx	vr26, r8, r3
vr27:
	andi.	r7, r6, 0x0010
	beq		vr28
	li		r8, off( vr27 )
	stvx	vr27, r8, r3
vr28:
	andi.	r7, r6, 0x0008
	beq		vr29
	li		r8, off( vr28 )
	stvx	vr28, r8, r3
vr29:
	andi.	r7, r6, 0x0004
	beq		vr30
	li		r8, off( vr29 )
	stvx	vr29, r8, r3
vr30:
	andi.	r7, r6, 0x0002
	beq		vr31
	li		r8, off( vr30 )
	stvx	vr30, r8, r3
vr31:
	andi.	r7, r6, 0x0001
	beq		done
	li		r8, off( vr31 )
	stvx	vr31, r8, r3
done:
	mfvscr	vr0					//	Load Vector Status and Control Register.
	li		r8, off( vscr )
	stvx	vr0, r8, r3			//	Store Vector Status and Control Register.
	
	stw		r6, off(vrsave)(r3)	//	Store VRSave.
	
	li		r3, 1				//	Return true.
	blr							//	We're outta here.
#undef	off
#endif
}

/****************************************************************************************
*	
*	Resuming Functions
*	
****************************************************************************************/
#pragma mark	-
#pragma mark	(Resuming Functions)

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Sat, Aug 5, 2000	Created.
	
	************************************************************************************/

	pascal
	void
ResumeRedShedThreadContext(
	RedShedThreadContext	*context )
{
	RequireRedShedThreadContext( context );
	
	context->resumer( context );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Jun 1, 1998	Created as ResumeRedShedThreadContext.
	wolf		Thu, Nov 19, 1998	Rolled in PowerPC code.
	wolf		Tue, Feb 16, 1999	In preparing for AltiVec, I rewrote the code
									to use the off( FIELD ) macro instead of hard-coded
									offsets.
	wolf		Thu, Aug 26, 1999	Rewrote, throwing out all optimizations.
									However, the code is smaller, easier to understand
									and I added AltiVec support.
									Once I'm sure it all works, I'll optimize it again.
	wolf		Fri, Feb 11, 2000	Added nofralloc assembler directive to PowerPC side.
									This stops CodeWarrior from generating automatic
									register save/restore functions.
	wolf		Sat, Aug 5, 2000	Broke from monolithic compile-time and run-time
									conditional ResumeRedShedThreadContext into dedicated
									function.
	
	************************************************************************************/

	asm
	pascal
	void
ResumeRedShedThreadContext68K(
	RedShedThreadContext* )
{
#if	!powerc
#define	off( FIELD )	struct(RedShedThreadContext68K.FIELD)
	//	68K
	movea.l		(sp)+, a0					//	Pop the return address (which we ignore).
	movea.l		(sp)+, a0					//	Pop the address to the context structure.
	movem.l		off(pc)(a0), d2-d7/a1-a7	//	Restore the registers from the context structure.
	#if	GENERATINGCFM
		moveq.l	#0, d0						//	Return false in register d0.
	#else
		move.l	#0, (sp)					//	Return false on the stack.
	#endif
	movea.l		d2, a0						//	Restore the pc.
	jmp			(a0)						//	We're outta here.
#undef	off
#endif
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Jun 1, 1998	Created as ResumeRedShedThreadContext.
	wolf		Thu, Nov 19, 1998	Rolled in PowerPC code.
	wolf		Tue, Feb 16, 1999	In preparing for AltiVec, I rewrote the code
									to use the off( FIELD ) macro instead of hard-coded
									offsets.
	wolf		Thu, Aug 26, 1999	Rewrote, throwing out all optimizations.
									However, the code is smaller, easier to understand
									and I added AltiVec support.
									Once I'm sure it all works, I'll optimize it again.
	wolf		Fri, Feb 11, 2000	Added nofralloc assembler directive to PowerPC side.
									This stops CodeWarrior from generating automatic
									register save/restore functions.
	wolf		Sat, Aug 5, 2000	Broke from monolithic compile-time and run-time
									conditional ResumeRedShedThreadContext into dedicated
									function.
	
	************************************************************************************/

	asm
	pascal
	void
ResumeRedShedThreadContext68881(
	RedShedThreadContext* )
{
#if	!powerc
#define	off( FIELD )	struct(RedShedThreadContext68881.FIELD)
	//	68K
	movea.l		(sp)+, a0					//	Pop the return address (which we ignore).
	movea.l		(sp)+, a0					//	Pop the address to the context structure.
	movem.l		off(pc)(a0), d2-d7/a1-a7	//	Restore the registers from the context structure.
	adda.l		#off(fp4), a0				//	Advance the pointer to the fp registers.
	opword		0xF210, 0xD00F				//	CWPro2 spits up on floating point 68K code.
//	fmovem.l	(a0), fp4-fp7				//	Restore floating point registers.
	#if	GENERATINGCFM
		moveq.l	#0, d0						//	Return false in register d0.
	#else
		move.l	#0, (sp)					//	Return false on the stack.
	#endif
	movea.l		d2, a0						//	Restore the pc.
	jmp			(a0)						//	We're outta here.
#undef	off
#endif
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Jun 1, 1998	Created as ResumeRedShedThreadContext.
	wolf		Thu, Nov 19, 1998	Rolled in PowerPC code.
	wolf		Tue, Feb 16, 1999	In preparing for AltiVec, I rewrote the code
									to use the off( FIELD ) macro instead of hard-coded
									offsets.
	wolf		Thu, Aug 26, 1999	Rewrote, throwing out all optimizations.
									However, the code is smaller, easier to understand
									and I added AltiVec support.
									Once I'm sure it all works, I'll optimize it again.
	wolf		Fri, Feb 11, 2000	Added nofralloc assembler directive to PowerPC side.
									This stops CodeWarrior from generating automatic
									register save/restore functions.
	wolf		Sat, Aug 5, 2000	Broke from monolithic compile-time and run-time
									conditional ResumeRedShedThreadContext into dedicated
									function.
	
	************************************************************************************/

	asm
	pascal
	void
ResumeRedShedThreadContextPPC(
	RedShedThreadContext* )
{
#if	powerc
#define	off( FIELD )	RedShedThreadContextPPC.FIELD
	nofralloc
	lwz		r4, off(pc)(r3)		//	Load old return address.
	mtlr	r4					//	Restore link register.
	lwz		r5, off(cr)(r3)		//	Load old condition register.
	mtcr	r5					//	Restore condition register.
	lwz		r1, off(sp)(r3)		//	Restore stack pointer.
	lwz		r2, off(toc)(r3)	//	Restore table of contents.
	stw		r2, 20(sp)
	lwz		r13, off(r13)(r3)	//	Restore r13 thru r31...
	lwz		r14, off(r14)(r3)
	lwz		r15, off(r15)(r3)
	lwz		r16, off(r16)(r3)
	lwz		r17, off(r17)(r3)
	lwz		r18, off(r18)(r3)
	lwz		r19, off(r19)(r3)
	lwz		r20, off(r20)(r3)
	lwz		r21, off(r21)(r3)
	lwz		r22, off(r22)(r3)
	lwz		r23, off(r23)(r3)
	lwz		r24, off(r24)(r3)
	lwz		r25, off(r25)(r3)
	lwz		r26, off(r26)(r3)
	lwz		r27, off(r27)(r3)
	lwz		r28, off(r28)(r3)
	lwz		r29, off(r29)(r3)
	lwz		r30, off(r30)(r3)
	lwz		r31, off(r31)(r3)
	lfd		fp14, off(fp14)(r3)	//	Restore fp14 thru fp31...
	lfd		fp15, off(fp15)(r3)
	lfd		fp16, off(fp16)(r3)
	lfd		fp17, off(fp17)(r3)
	lfd		fp18, off(fp18)(r3)
	lfd		fp19, off(fp19)(r3)
	lfd		fp20, off(fp20)(r3)
	lfd		fp21, off(fp21)(r3)
	lfd		fp22, off(fp22)(r3)
	lfd		fp23, off(fp23)(r3)
	lfd		fp24, off(fp24)(r3)
	lfd		fp25, off(fp25)(r3)
	lfd		fp26, off(fp26)(r3)
	lfd		fp27, off(fp27)(r3)
	lfd		fp28, off(fp28)(r3)
	lfd		fp29, off(fp29)(r3)
	lfd		fp30, off(fp30)(r3)
	lfd		fp31, off(fp31)(r3)
	lfd		fp0, off(fpscr)(r3)	//	Load old floating point status and control register.
	mtfs	fp0					//	Restore floating point status and control register.
	li		r3, 0				//	Return false.
	blr							//	We're outta here.
#undef	off
#endif
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Jun 1, 1998	Created as ResumeRedShedThreadContext.
	wolf		Thu, Nov 19, 1998	Rolled in PowerPC code.
	wolf		Tue, Feb 16, 1999	In preparing for AltiVec, I rewrote the code
									to use the off( FIELD ) macro instead of hard-coded
									offsets.
	wolf		Thu, Aug 26, 1999	Rewrote, throwing out all optimizations.
									However, the code is smaller, easier to understand
									and I added AltiVec support.
									Once I'm sure it all works, I'll optimize it again.
	wolf		Fri, Feb 11, 2000	Added nofralloc assembler directive to PowerPC side.
									This stops CodeWarrior from generating automatic
									register save/restore functions.
	wolf		Sat, Aug 5, 2000	Broke from monolithic compile-time and run-time
									conditional ResumeRedShedThreadContext into dedicated
									function.
	
	************************************************************************************/

	asm
	pascal
	void
ResumeRedShedThreadContextPPCFP(
	RedShedThreadContext* )
{
#if	powerc
#define	off( FIELD )	RedShedThreadContextPPCFP.FIELD
	nofralloc
	lwz		r4, off(pc)(r3)		//	Load old return address.
	mtlr	r4					//	Restore link register.
	lwz		r5, off(cr)(r3)		//	Load old condition register.
	mtcr	r5					//	Restore condition register.
	lwz		r1, off(sp)(r3)		//	Restore stack pointer.
	lwz		r2, off(toc)(r3)	//	Restore table of contents.
	stw		r2, 20(sp)
	lwz		r13, off(r13)(r3)	//	Restore r13 thru r31...
	lwz		r14, off(r14)(r3)
	lwz		r15, off(r15)(r3)
	lwz		r16, off(r16)(r3)
	lwz		r17, off(r17)(r3)
	lwz		r18, off(r18)(r3)
	lwz		r19, off(r19)(r3)
	lwz		r20, off(r20)(r3)
	lwz		r21, off(r21)(r3)
	lwz		r22, off(r22)(r3)
	lwz		r23, off(r23)(r3)
	lwz		r24, off(r24)(r3)
	lwz		r25, off(r25)(r3)
	lwz		r26, off(r26)(r3)
	lwz		r27, off(r27)(r3)
	lwz		r28, off(r28)(r3)
	lwz		r29, off(r29)(r3)
	lwz		r30, off(r30)(r3)
	lwz		r31, off(r31)(r3)
	lfd		fp0, off(fp0)(r3)	//	Restore fp0 thru fp31...
	lfd		fp1, off(fp1)(r3)
	lfd		fp2, off(fp2)(r3)
	lfd		fp3, off(fp3)(r3)
	lfd		fp4, off(fp4)(r3)
	lfd		fp5, off(fp5)(r3)
	lfd		fp6, off(fp6)(r3)
	lfd		fp7, off(fp7)(r3)
	lfd		fp8, off(fp8)(r3)
	lfd		fp9, off(fp9)(r3)
	lfd		fp10, off(fp10)(r3)
	lfd		fp11, off(fp11)(r3)
	lfd		fp12, off(fp12)(r3)
	lfd		fp13, off(fp13)(r3)
	lfd		fp14, off(fp14)(r3)
	lfd		fp15, off(fp15)(r3)
	lfd		fp16, off(fp16)(r3)
	lfd		fp17, off(fp17)(r3)
	lfd		fp18, off(fp18)(r3)
	lfd		fp19, off(fp19)(r3)
	lfd		fp20, off(fp20)(r3)
	lfd		fp21, off(fp21)(r3)
	lfd		fp22, off(fp22)(r3)
	lfd		fp23, off(fp23)(r3)
	lfd		fp24, off(fp24)(r3)
	lfd		fp25, off(fp25)(r3)
	lfd		fp26, off(fp26)(r3)
	lfd		fp27, off(fp27)(r3)
	lfd		fp28, off(fp28)(r3)
	lfd		fp29, off(fp29)(r3)
	lfd		fp30, off(fp30)(r3)
	lfd		fp31, off(fp31)(r3)
	lfd		fp0, off(fpscr)(r3)	//	Load old floating point status and control register.
	mtfs	fp0					//	Restore floating point status and control register.
	li		r3, 0				//	Return false.
	blr							//	We're outta here.
#undef	off
#endif
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Jun 1, 1998	Created as ResumeRedShedThreadContext.
	wolf		Thu, Nov 19, 1998	Rolled in PowerPC code.
	wolf		Tue, Feb 16, 1999	In preparing for AltiVec, I rewrote the code
									to use the off( FIELD ) macro instead of hard-coded
									offsets.
	wolf		Thu, Aug 26, 1999	Rewrote, throwing out all optimizations.
									However, the code is smaller, easier to understand
									and I added AltiVec support.
									Once I'm sure it all works, I'll optimize it again.
	wolf		Fri, Feb 11, 2000	Added nofralloc assembler directive to PowerPC side.
									This stops CodeWarrior from generating automatic
									register save/restore functions.
	wolf		Sat, Aug 5, 2000	Broke from monolithic compile-time and run-time
									conditional ResumeRedShedThreadContext into dedicated
									function.
	
	************************************************************************************/

	asm
	pascal
	void
ResumeRedShedThreadContextAltiVec(
	RedShedThreadContext* )
{
#if	powerc
#define	off( FIELD )	RedShedThreadContextAltiVec.FIELD
	nofralloc
	lwz		r4, off(pc)(r3)		//	Load old return address.
	mtlr	r4					//	Restore link register.
	lwz		r5, off(cr)(r3)		//	Load old condition register.
	mtcr	r5					//	Restore condition register.
	lwz		r1, off(sp)(r3)		//	Restore stack pointer.
	lwz		r2, off(toc)(r3)	//	Restore table of contents.
	stw		r2, 20(sp)
	lwz		r13, off(r13)(r3)	//	Restore r13 thru r31...
	lwz		r14, off(r14)(r3)
	lwz		r15, off(r15)(r3)
	lwz		r16, off(r16)(r3)
	lwz		r17, off(r17)(r3)
	lwz		r18, off(r18)(r3)
	lwz		r19, off(r19)(r3)
	lwz		r20, off(r20)(r3)
	lwz		r21, off(r21)(r3)
	lwz		r22, off(r22)(r3)
	lwz		r23, off(r23)(r3)
	lwz		r24, off(r24)(r3)
	lwz		r25, off(r25)(r3)
	lwz		r26, off(r26)(r3)
	lwz		r27, off(r27)(r3)
	lwz		r28, off(r28)(r3)
	lwz		r29, off(r29)(r3)
	lwz		r30, off(r30)(r3)
	lwz		r31, off(r31)(r3)
	lfd		fp14, off(fp14)(r3)	//	Restore fp14 thru fp31...
	lfd		fp15, off(fp15)(r3)
	lfd		fp16, off(fp16)(r3)
	lfd		fp17, off(fp17)(r3)
	lfd		fp18, off(fp18)(r3)
	lfd		fp19, off(fp19)(r3)
	lfd		fp20, off(fp20)(r3)
	lfd		fp21, off(fp21)(r3)
	lfd		fp22, off(fp22)(r3)
	lfd		fp23, off(fp23)(r3)
	lfd		fp24, off(fp24)(r3)
	lfd		fp25, off(fp25)(r3)
	lfd		fp26, off(fp26)(r3)
	lfd		fp27, off(fp27)(r3)
	lfd		fp28, off(fp28)(r3)
	lfd		fp29, off(fp29)(r3)
	lfd		fp30, off(fp30)(r3)
	lfd		fp31, off(fp31)(r3)
	lfd		fp0, off(fpscr)(r3)	//	Load old floating point status and control register.
	mtfs	fp0					//	Restore floating point status and control register.
	//	AltiVec
	li		r6, 0x0001
	mtspr	256, r6				//	Set VRSave to vr31.
	
	li		r8, off( vscr )
	lvx		vr31, r8, r3		//	Load old Vector Status and Control Register.
	mtvscr	vr31				//	Restore Vector Status and Control Register.
	
	lwz		r6, off(vrsave)(r3)	//	Load old VRSave.
	mtspr	256, r6				//	Restore VRSave.
vr0:
	andis.	r7, r6, 0x8000
	beq		vr1
	li		r8, off( vr0 )
	lvx		vr0, r8, r3
vr1:
	andis.	r7, r6, 0x4000
	beq		vr2
	li		r8, off( vr1 )
	lvx		vr1, r8, r3
vr2:
	andis.	r7, r6, 0x2000
	beq		vr3
	li		r8, off( vr2 )
	lvx		vr2, r8, r3
vr3:
	andis.	r7, r6, 0x1000
	beq		vr4
	li		r8, off( vr3 )
	lvx		vr3, r8, r3
vr4:
	andis.	r7, r6, 0x0800
	beq		vr5
	li		r8, off( vr4 )
	lvx		vr4, r8, r3
vr5:
	andis.	r7, r6, 0x0400
	beq		vr6
	li		r8, off( vr5 )
	lvx		vr5, r8, r3
vr6:
	andis.	r7, r6, 0x0200
	beq		vr7
	li		r8, off( vr6 )
	lvx		vr6, r8, r3
vr7:
	andis.	r7, r6, 0x0100
	beq		vr8
	li		r8, off( vr7 )
	lvx		vr7, r8, r3
vr8:
	andis.	r7, r6, 0x0080
	beq		vr9
	li		r8, off( vr8 )
	lvx		vr8, r8, r3
vr9:
	andis.	r7, r6, 0x0040
	beq		vr10
	li		r8, off( vr9 )
	lvx		vr9, r8, r3
vr10:
	andis.	r7, r6, 0x0020
	beq		vr11
	li		r8, off( vr10 )
	lvx		vr10, r8, r3
vr11:
	andis.	r7, r6, 0x0010
	beq		vr12
	li		r8, off( vr11 )
	lvx		vr11, r8, r3
vr12:
	andis.	r7, r6, 0x0008
	beq		vr13
	li		r8, off( vr12 )
	lvx		vr12, r8, r3
vr13:
	andis.	r7, r6, 0x0004
	beq		vr14
	li		r8, off( vr13 )
	lvx		vr13, r8, r3
vr14:
	andis.	r7, r6, 0x0002
	beq		vr15
	li		r8, off( vr14 )
	lvx		vr14, r8, r3
vr15:
	andis.	r7, r6, 0x0001
	beq		vr16
	li		r8, off( vr15 )
	lvx		vr15, r8, r3
vr16:
	andi.	r7, r6, 0x8000
	beq		vr17
	li		r8, off( vr16 )
	lvx		vr16, r8, r3
vr17:
	andi.	r7, r6, 0x4000
	beq		vr18
	li		r8, off( vr17 )
	lvx		vr17, r8, r3
vr18:
	andi.	r7, r6, 0x2000
	beq		vr19
	li		r8, off( vr18 )
	lvx		vr18, r8, r3
vr19:
	andi.	r7, r6, 0x1000
	beq		vr20
	li		r8, off( vr19 )
	lvx		vr19, r8, r3
vr20:
	andi.	r7, r6, 0x0800
	beq		vr21
	li		r8, off( vr20 )
	lvx		vr20, r8, r3
vr21:
	andi.	r7, r6, 0x0400
	beq		vr22
	li		r8, off( vr21 )
	lvx		vr21, r8, r3
vr22:
	andi.	r7, r6, 0x0200
	beq		vr23
	li		r8, off( vr22 )
	lvx		vr22, r8, r3
vr23:
	andi.	r7, r6, 0x0100
	beq		vr24
	li		r8, off( vr23 )
	lvx		vr23, r8, r3
vr24:
	andi.	r7, r6, 0x0080
	beq		vr25
	li		r8, off( vr24 )
	lvx		vr24, r8, r3
vr25:
	andi.	r7, r6, 0x0040
	beq		vr26
	li		r8, off( vr25 )
	lvx		vr25, r8, r3
vr26:
	andi.	r7, r6, 0x0020
	beq		vr27
	li		r8, off( vr26 )
	lvx		vr26, r8, r3
vr27:
	andi.	r7, r6, 0x0010
	beq		vr28
	li		r8, off( vr27 )
	lvx		vr27, r8, r3
vr28:
	andi.	r7, r6, 0x0008
	beq		vr29
	li		r8, off( vr28 )
	lvx		vr28, r8, r3
vr29:
	andi.	r7, r6, 0x0004
	beq		vr30
	li		r8, off( vr29 )
	lvx		vr29, r8, r3
vr30:
	andi.	r7, r6, 0x0002
	beq		vr31
	li		r8, off( vr30 )
	lvx		vr30, r8, r3
vr31:
	andi.	r7, r6, 0x0001
	beq		done
	li		r8, off( vr31 )
	lvx		vr31, r8, r3
done:
	
	li		r3, 0				//	Return false.
	blr							//	We're outta here.
#undef	off
#endif
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Jun 1, 1998	Created as ResumeRedShedThreadContext.
	wolf		Thu, Nov 19, 1998	Rolled in PowerPC code.
	wolf		Tue, Feb 16, 1999	In preparing for AltiVec, I rewrote the code
									to use the off( FIELD ) macro instead of hard-coded
									offsets.
	wolf		Thu, Aug 26, 1999	Rewrote, throwing out all optimizations.
									However, the code is smaller, easier to understand
									and I added AltiVec support.
									Once I'm sure it all works, I'll optimize it again.
	wolf		Fri, Feb 11, 2000	Added nofralloc assembler directive to PowerPC side.
									This stops CodeWarrior from generating automatic
									register save/restore functions.
	wolf		Sat, Aug 5, 2000	Broke from monolithic compile-time and run-time
									conditional ResumeRedShedThreadContext into dedicated
									function.
	
	************************************************************************************/

	asm
	pascal
	void
ResumeRedShedThreadContextAltiVecFP(
	RedShedThreadContext* )
{
#if	powerc
#define	off( FIELD )	RedShedThreadContextAltiVecFP.FIELD
	nofralloc
	lwz		r4, off(pc)(r3)		//	Load old return address.
	mtlr	r4					//	Restore link register.
	lwz		r5, off(cr)(r3)		//	Load old condition register.
	mtcr	r5					//	Restore condition register.
	lwz		r1, off(sp)(r3)		//	Restore stack pointer.
	lwz		r2, off(toc)(r3)	//	Restore table of contents.
	stw		r2, 20(sp)
	lwz		r13, off(r13)(r3)	//	Restore r13 thru r31...
	lwz		r14, off(r14)(r3)
	lwz		r15, off(r15)(r3)
	lwz		r16, off(r16)(r3)
	lwz		r17, off(r17)(r3)
	lwz		r18, off(r18)(r3)
	lwz		r19, off(r19)(r3)
	lwz		r20, off(r20)(r3)
	lwz		r21, off(r21)(r3)
	lwz		r22, off(r22)(r3)
	lwz		r23, off(r23)(r3)
	lwz		r24, off(r24)(r3)
	lwz		r25, off(r25)(r3)
	lwz		r26, off(r26)(r3)
	lwz		r27, off(r27)(r3)
	lwz		r28, off(r28)(r3)
	lwz		r29, off(r29)(r3)
	lwz		r30, off(r30)(r3)
	lwz		r31, off(r31)(r3)
	lfd		fp0, off(fp0)(r3)	//	Restore fp0 thru fp31...
	lfd		fp1, off(fp1)(r3)
	lfd		fp2, off(fp2)(r3)
	lfd		fp3, off(fp3)(r3)
	lfd		fp4, off(fp4)(r3)
	lfd		fp5, off(fp5)(r3)
	lfd		fp6, off(fp6)(r3)
	lfd		fp7, off(fp7)(r3)
	lfd		fp8, off(fp8)(r3)
	lfd		fp9, off(fp9)(r3)
	lfd		fp10, off(fp10)(r3)
	lfd		fp11, off(fp11)(r3)
	lfd		fp12, off(fp12)(r3)
	lfd		fp13, off(fp13)(r3)
	lfd		fp14, off(fp14)(r3)
	lfd		fp15, off(fp15)(r3)
	lfd		fp16, off(fp16)(r3)
	lfd		fp17, off(fp17)(r3)
	lfd		fp18, off(fp18)(r3)
	lfd		fp19, off(fp19)(r3)
	lfd		fp20, off(fp20)(r3)
	lfd		fp21, off(fp21)(r3)
	lfd		fp22, off(fp22)(r3)
	lfd		fp23, off(fp23)(r3)
	lfd		fp24, off(fp24)(r3)
	lfd		fp25, off(fp25)(r3)
	lfd		fp26, off(fp26)(r3)
	lfd		fp27, off(fp27)(r3)
	lfd		fp28, off(fp28)(r3)
	lfd		fp29, off(fp29)(r3)
	lfd		fp30, off(fp30)(r3)
	lfd		fp31, off(fp31)(r3)
	lfd		fp0, off(fpscr)(r3)	//	Load old floating point status and control register.
	mtfs	fp0					//	Restore floating point status and control register.
	//	AltiVec
	li		r6, 0x0001
	mtspr	256, r6				//	Set VRSave to vr31.
	
	li		r8, off( vscr )
	lvx		vr31, r8, r3		//	Load old Vector Status and Control Register.
	mtvscr	vr31				//	Restore Vector Status and Control Register.
	
	lwz		r6, off(vrsave)(r3)	//	Load old VRSave.
	mtspr	256, r6				//	Restore VRSave.
vr0:
	andis.	r7, r6, 0x8000
	beq		vr1
	li		r8, off( vr0 )
	lvx		vr0, r8, r3
vr1:
	andis.	r7, r6, 0x4000
	beq		vr2
	li		r8, off( vr1 )
	lvx		vr1, r8, r3
vr2:
	andis.	r7, r6, 0x2000
	beq		vr3
	li		r8, off( vr2 )
	lvx		vr2, r8, r3
vr3:
	andis.	r7, r6, 0x1000
	beq		vr4
	li		r8, off( vr3 )
	lvx		vr3, r8, r3
vr4:
	andis.	r7, r6, 0x0800
	beq		vr5
	li		r8, off( vr4 )
	lvx		vr4, r8, r3
vr5:
	andis.	r7, r6, 0x0400
	beq		vr6
	li		r8, off( vr5 )
	lvx		vr5, r8, r3
vr6:
	andis.	r7, r6, 0x0200
	beq		vr7
	li		r8, off( vr6 )
	lvx		vr6, r8, r3
vr7:
	andis.	r7, r6, 0x0100
	beq		vr8
	li		r8, off( vr7 )
	lvx		vr7, r8, r3
vr8:
	andis.	r7, r6, 0x0080
	beq		vr9
	li		r8, off( vr8 )
	lvx		vr8, r8, r3
vr9:
	andis.	r7, r6, 0x0040
	beq		vr10
	li		r8, off( vr9 )
	lvx		vr9, r8, r3
vr10:
	andis.	r7, r6, 0x0020
	beq		vr11
	li		r8, off( vr10 )
	lvx		vr10, r8, r3
vr11:
	andis.	r7, r6, 0x0010
	beq		vr12
	li		r8, off( vr11 )
	lvx		vr11, r8, r3
vr12:
	andis.	r7, r6, 0x0008
	beq		vr13
	li		r8, off( vr12 )
	lvx		vr12, r8, r3
vr13:
	andis.	r7, r6, 0x0004
	beq		vr14
	li		r8, off( vr13 )
	lvx		vr13, r8, r3
vr14:
	andis.	r7, r6, 0x0002
	beq		vr15
	li		r8, off( vr14 )
	lvx		vr14, r8, r3
vr15:
	andis.	r7, r6, 0x0001
	beq		vr16
	li		r8, off( vr15 )
	lvx		vr15, r8, r3
vr16:
	andi.	r7, r6, 0x8000
	beq		vr17
	li		r8, off( vr16 )
	lvx		vr16, r8, r3
vr17:
	andi.	r7, r6, 0x4000
	beq		vr18
	li		r8, off( vr17 )
	lvx		vr17, r8, r3
vr18:
	andi.	r7, r6, 0x2000
	beq		vr19
	li		r8, off( vr18 )
	lvx		vr18, r8, r3
vr19:
	andi.	r7, r6, 0x1000
	beq		vr20
	li		r8, off( vr19 )
	lvx		vr19, r8, r3
vr20:
	andi.	r7, r6, 0x0800
	beq		vr21
	li		r8, off( vr20 )
	lvx		vr20, r8, r3
vr21:
	andi.	r7, r6, 0x0400
	beq		vr22
	li		r8, off( vr21 )
	lvx		vr21, r8, r3
vr22:
	andi.	r7, r6, 0x0200
	beq		vr23
	li		r8, off( vr22 )
	lvx		vr22, r8, r3
vr23:
	andi.	r7, r6, 0x0100
	beq		vr24
	li		r8, off( vr23 )
	lvx		vr23, r8, r3
vr24:
	andi.	r7, r6, 0x0080
	beq		vr25
	li		r8, off( vr24 )
	lvx		vr24, r8, r3
vr25:
	andi.	r7, r6, 0x0040
	beq		vr26
	li		r8, off( vr25 )
	lvx		vr25, r8, r3
vr26:
	andi.	r7, r6, 0x0020
	beq		vr27
	li		r8, off( vr26 )
	lvx		vr26, r8, r3
vr27:
	andi.	r7, r6, 0x0010
	beq		vr28
	li		r8, off( vr27 )
	lvx		vr27, r8, r3
vr28:
	andi.	r7, r6, 0x0008
	beq		vr29
	li		r8, off( vr28 )
	lvx		vr28, r8, r3
vr29:
	andi.	r7, r6, 0x0004
	beq		vr30
	li		r8, off( vr29 )
	lvx		vr29, r8, r3
vr30:
	andi.	r7, r6, 0x0002
	beq		vr31
	li		r8, off( vr30 )
	lvx		vr30, r8, r3
vr31:
	andi.	r7, r6, 0x0001
	beq		done
	li		r8, off( vr31 )
	lvx		vr31, r8, r3
done:
	
	li		r3, 0				//	Return false.
	blr							//	We're outta here.
#undef	off
#endif
}



See more files for this project here

redshed

Code for Mac+WebObjects.

Project homepage: http://sourceforge.net/projects/redshed
Programming language(s): C,Java,Objective C
License: other

  RedShedThreadContext.c
  RedShedThreadContext.h
  RedShedThreads.c
  RedShedThreads.h