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