Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

vm_ppc_new.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 // vm_ppc.c
00023 // ppc dynamic compiler
00024 
00025 #include "vm_local.h"
00026 
00027 #pragma opt_pointer_analysis off
00028 
00029 #define DEBUG_VM 0
00030 
00031 #if DEBUG_VM
00032 static char *opnames[256] = {
00033     "OP_UNDEF", 
00034 
00035     "OP_IGNORE", 
00036 
00037     "OP_BREAK",
00038 
00039     "OP_ENTER",
00040     "OP_LEAVE",
00041     "OP_CALL",
00042     "OP_PUSH",
00043     "OP_POP",
00044 
00045     "OP_CONST",
00046 
00047     "OP_LOCAL",
00048 
00049     "OP_JUMP",
00050 
00051     //-------------------
00052 
00053     "OP_EQ",
00054     "OP_NE",
00055 
00056     "OP_LTI",
00057     "OP_LEI",
00058     "OP_GTI",
00059     "OP_GEI",
00060 
00061     "OP_LTU",
00062     "OP_LEU",
00063     "OP_GTU",
00064     "OP_GEU",
00065 
00066     "OP_EQF",
00067     "OP_NEF",
00068 
00069     "OP_LTF",
00070     "OP_LEF",
00071     "OP_GTF",
00072     "OP_GEF",
00073 
00074     //-------------------
00075 
00076     "OP_LOAD1",
00077     "OP_LOAD2",
00078     "OP_LOAD4",
00079     "OP_STORE1",
00080     "OP_STORE2",
00081     "OP_STORE4",
00082     "OP_ARG",
00083 
00084     "OP_BLOCK_COPY",
00085 
00086     //-------------------
00087 
00088     "OP_SEX8",
00089     "OP_SEX16",
00090 
00091     "OP_NEGI",
00092     "OP_ADD",
00093     "OP_SUB",
00094     "OP_DIVI",
00095     "OP_DIVU",
00096     "OP_MODI",
00097     "OP_MODU",
00098     "OP_MULI",
00099     "OP_MULU",
00100 
00101     "OP_BAND",
00102     "OP_BOR",
00103     "OP_BXOR",
00104     "OP_BCOM",
00105 
00106     "OP_LSH",
00107     "OP_RSHI",
00108     "OP_RSHU",
00109 
00110     "OP_NEGF",
00111     "OP_ADDF",
00112     "OP_SUBF",
00113     "OP_DIVF",
00114     "OP_MULF",
00115 
00116     "OP_CVIF",
00117     "OP_CVFI"
00118 };
00119 #endif
00120 
00121 typedef enum {
00122     R_REAL_STACK = 1,
00123     // registers 3-11 are the parameter passing registers
00124     
00125     // state
00126     R_STACK = 3,            // local
00127     R_OPSTACK,              // global
00128 
00129     // constants    
00130     R_MEMBASE,          // global
00131     R_MEMMASK,
00132     R_ASMCALL,          // global
00133     R_INSTRUCTIONS,     // global
00134     R_NUM_INSTRUCTIONS, // global
00135     R_CVM,              // currentVM
00136     
00137     // temps
00138     R_TOP = 11,
00139     R_SECOND = 12,
00140     R_EA = 2                // effective address calculation
00141      
00142 } regNums_t;
00143 
00144 #define RG_REAL_STACK       r1
00145 #define RG_STACK            r3
00146 #define RG_OPSTACK          r4
00147 #define RG_MEMBASE          r5
00148 #define RG_MEMMASK          r6
00149 #define RG_ASMCALL          r7
00150 #define RG_INSTRUCTIONS     r8
00151 #define RG_NUM_INSTRUCTIONS r9
00152 #define RG_CVM              r10
00153 #define RG_TOP              r12
00154 #define RG_SECOND           r13
00155 #define RG_EA               r14
00156 
00157 // The deepest value I saw in the Quake3 games was 9.
00158 #define OP_STACK_MAX_DEPTH  12
00159 
00160 // These are all volatile and thus must be saved
00161 // upon entry to the VM code.
00162 static int opStackIntRegisters[OP_STACK_MAX_DEPTH] =
00163 {
00164     16, 17, 18, 19,
00165     20, 21, 22, 23,
00166     24, 25, 26, 27
00167 };
00168 
00169 static unsigned int *opStackLoadInstructionAddr[OP_STACK_MAX_DEPTH];
00170 
00171 // We use different registers for the floating point
00172 // operand stack (these are volatile in the PPC ABI)
00173 static int opStackFloatRegisters[OP_STACK_MAX_DEPTH] =
00174 {
00175     0, 1, 2, 3,
00176     4, 5, 6, 7,
00177     8, 9, 10, 11
00178 };
00179 
00180 static int opStackRegType[OP_STACK_MAX_DEPTH] =
00181 {
00182     0, 0, 0, 0,
00183     0, 0, 0, 0,
00184     0, 0, 0, 0
00185 };
00186 
00187 // this doesn't have the low order bits set for instructions i'm not using...
00188 typedef enum {
00189     PPC_TDI     = 0x08000000,
00190     PPC_TWI     = 0x0c000000,
00191     PPC_MULLI   = 0x1c000000,
00192     PPC_SUBFIC  = 0x20000000,
00193     PPC_CMPI    = 0x28000000,
00194     PPC_CMPLI   = 0x2c000000,
00195     PPC_ADDIC   = 0x30000000,
00196     PPC_ADDIC_  = 0x34000000,
00197     PPC_ADDI    = 0x38000000,
00198     PPC_ADDIS   = 0x3c000000,
00199     PPC_BC      = 0x40000000,
00200     PPC_SC      = 0x44000000,
00201     PPC_B       = 0x48000000,
00202 
00203     PPC_MCRF    = 0x4c000000,
00204     PPC_BCLR    = 0x4c000020,
00205     PPC_RFID    = 0x4c000000,
00206     PPC_CRNOR   = 0x4c000000,
00207     PPC_RFI     = 0x4c000000,
00208     PPC_CRANDC  = 0x4c000000,
00209     PPC_ISYNC   = 0x4c000000,
00210     PPC_CRXOR   = 0x4c000000,
00211     PPC_CRNAND  = 0x4c000000,
00212     PPC_CREQV   = 0x4c000000,
00213     PPC_CRORC   = 0x4c000000,
00214     PPC_CROR    = 0x4c000000,
00215 //------------
00216     PPC_BCCTR   = 0x4c000420,
00217     PPC_RLWIMI  = 0x50000000,
00218     PPC_RLWINM  = 0x54000000,
00219     PPC_RLWNM   = 0x5c000000,
00220     PPC_ORI     = 0x60000000,
00221     PPC_ORIS    = 0x64000000,
00222     PPC_XORI    = 0x68000000,
00223     PPC_XORIS   = 0x6c000000,
00224     PPC_ANDI_   = 0x70000000,
00225     PPC_ANDIS_  = 0x74000000,
00226     PPC_RLDICL  = 0x78000000,
00227     PPC_RLDICR  = 0x78000000,
00228     PPC_RLDIC   = 0x78000000,
00229     PPC_RLDIMI  = 0x78000000,
00230     PPC_RLDCL   = 0x78000000,
00231     PPC_RLDCR   = 0x78000000,
00232     PPC_CMP     = 0x7c000000,
00233     PPC_TW      = 0x7c000000,
00234     PPC_SUBFC   = 0x7c000010,
00235     PPC_MULHDU  = 0x7c000000,
00236     PPC_ADDC    = 0x7c000014,
00237     PPC_MULHWU  = 0x7c000000,
00238     PPC_MFCR    = 0x7c000000,
00239     PPC_LWAR    = 0x7c000000,
00240     PPC_LDX     = 0x7c000000,
00241     PPC_LWZX    = 0x7c00002e,
00242     PPC_SLW     = 0x7c000030,
00243     PPC_CNTLZW  = 0x7c000000,
00244     PPC_SLD     = 0x7c000000,
00245     PPC_AND     = 0x7c000038,
00246     PPC_CMPL    = 0x7c000040,
00247     PPC_SUBF    = 0x7c000050,
00248     PPC_LDUX    = 0x7c000000,
00249 //------------
00250     PPC_DCBST   = 0x7c000000,
00251     PPC_LWZUX   = 0x7c00006c,
00252     PPC_CNTLZD  = 0x7c000000,
00253     PPC_ANDC    = 0x7c000000,
00254     PPC_TD      = 0x7c000000,
00255     PPC_MULHD   = 0x7c000000,
00256     PPC_MULHW   = 0x7c000000,
00257     PPC_MTSRD   = 0x7c000000,
00258     PPC_MFMSR   = 0x7c000000,
00259     PPC_LDARX   = 0x7c000000,
00260     PPC_DCBF    = 0x7c000000,
00261     PPC_LBZX    = 0x7c0000ae,
00262     PPC_NEG     = 0x7c000000,
00263     PPC_MTSRDIN = 0x7c000000,
00264     PPC_LBZUX   = 0x7c000000,
00265     PPC_NOR     = 0x7c0000f8,
00266     PPC_SUBFE   = 0x7c000000,
00267     PPC_ADDE    = 0x7c000000,
00268     PPC_MTCRF   = 0x7c000000,
00269     PPC_MTMSR   = 0x7c000000,
00270     PPC_STDX    = 0x7c000000,
00271     PPC_STWCX_  = 0x7c000000,
00272     PPC_STWX    = 0x7c00012e,
00273     PPC_MTMSRD  = 0x7c000000,
00274     PPC_STDUX   = 0x7c000000,
00275     PPC_STWUX   = 0x7c00016e,
00276     PPC_SUBFZE  = 0x7c000000,
00277     PPC_ADDZE   = 0x7c000000,
00278     PPC_MTSR    = 0x7c000000,
00279     PPC_STDCX_  = 0x7c000000,
00280     PPC_STBX    = 0x7c0001ae,
00281     PPC_SUBFME  = 0x7c000000,
00282     PPC_MULLD   = 0x7c000000,
00283 //------------
00284     PPC_ADDME   = 0x7c000000,
00285     PPC_MULLW   = 0x7c0001d6,
00286     PPC_MTSRIN  = 0x7c000000,
00287     PPC_DCBTST  = 0x7c000000,
00288     PPC_STBUX   = 0x7c000000,
00289     PPC_ADD     = 0x7c000214,
00290     PPC_DCBT    = 0x7c000000,
00291     PPC_LHZX    = 0x7c00022e,
00292     PPC_EQV     = 0x7c000000,
00293     PPC_TLBIE   = 0x7c000000,
00294     PPC_ECIWX   = 0x7c000000,
00295     PPC_LHZUX   = 0x7c000000,
00296     PPC_XOR     = 0x7c000278,
00297     PPC_MFSPR   = 0x7c0002a6,
00298     PPC_LWAX    = 0x7c000000,
00299     PPC_LHAX    = 0x7c000000,
00300     PPC_TLBIA   = 0x7c000000,
00301     PPC_MFTB    = 0x7c000000,
00302     PPC_LWAUX   = 0x7c000000,
00303     PPC_LHAUX   = 0x7c000000,
00304     PPC_STHX    = 0x7c00032e,
00305     PPC_ORC     = 0x7c000338,
00306     PPC_SRADI   = 0x7c000000,
00307     PPC_SLBIE   = 0x7c000000,
00308     PPC_ECOWX   = 0x7c000000,
00309     PPC_STHUX   = 0x7c000000,
00310     PPC_OR      = 0x7c000378,
00311     PPC_DIVDU   = 0x7c000000,
00312     PPC_DIVWU   = 0x7c000396,
00313     PPC_MTSPR   = 0x7c0003a6,
00314     PPC_DCBI    = 0x7c000000,
00315     PPC_NAND    = 0x7c000000,
00316     PPC_DIVD    = 0x7c000000,
00317 //------------
00318     PPC_DIVW    = 0x7c0003d6,
00319     PPC_SLBIA   = 0x7c000000,
00320     PPC_MCRXR   = 0x7c000000,
00321     PPC_LSWX    = 0x7c000000,
00322     PPC_LWBRX   = 0x7c000000,
00323     PPC_LFSX    = 0x7c00042e,
00324     PPC_SRW     = 0x7c000430,
00325     PPC_SRD     = 0x7c000000,
00326     PPC_TLBSYNC = 0x7c000000,
00327     PPC_LFSUX   = 0x7c000000,
00328     PPC_MFSR    = 0x7c000000,
00329     PPC_LSWI    = 0x7c000000,
00330     PPC_SYNC    = 0x7c000000,
00331     PPC_LFDX    = 0x7c000000,
00332     PPC_LFDUX   = 0x7c000000,
00333     PPC_MFSRIN  = 0x7c000000,
00334     PPC_STSWX   = 0x7c000000,
00335     PPC_STWBRX  = 0x7c000000,
00336     PPC_STFSX   = 0x7c00052e,
00337     PPC_STFSUX  = 0x7c000000,
00338     PPC_STSWI   = 0x7c000000,
00339     PPC_STFDX   = 0x7c000000,
00340     PPC_DCBA    = 0x7c000000,
00341     PPC_STFDUX  = 0x7c000000,
00342     PPC_LHBRX   = 0x7c000000,
00343     PPC_SRAW    = 0x7c000630,
00344     PPC_SRAD    = 0x7c000000,
00345     PPC_SRAWI   = 0x7c000000,
00346     PPC_EIEIO   = 0x7c000000,
00347     PPC_STHBRX  = 0x7c000000,
00348     PPC_EXTSH   = 0x7c000734,
00349     PPC_EXTSB   = 0x7c000774,
00350     PPC_ICBI    = 0x7c000000,
00351 //------------
00352     PPC_STFIWX  = 0x7c0007ae,
00353     PPC_EXTSW   = 0x7c000000,
00354     PPC_DCBZ    = 0x7c000000,
00355     PPC_LWZ     = 0x80000000,
00356     PPC_LWZU    = 0x84000000,
00357     PPC_LBZ     = 0x88000000,
00358     PPC_LBZU    = 0x8c000000,
00359     PPC_STW     = 0x90000000,
00360     PPC_STWU    = 0x94000000,
00361     PPC_STB     = 0x98000000,
00362     PPC_STBU    = 0x9c000000,
00363     PPC_LHZ     = 0xa0000000,
00364     PPC_LHZU    = 0xa4000000,
00365     PPC_LHA     = 0xa8000000,
00366     PPC_LHAU    = 0xac000000,
00367     PPC_STH     = 0xb0000000,
00368     PPC_STHU    = 0xb4000000,
00369     PPC_LMW     = 0xb8000000,
00370     PPC_STMW    = 0xbc000000,
00371     PPC_LFS     = 0xc0000000,
00372     PPC_LFSU    = 0xc4000000,
00373     PPC_LFD     = 0xc8000000,
00374     PPC_LFDU    = 0xcc000000,
00375     PPC_STFS    = 0xd0000000,
00376     PPC_STFSU   = 0xd4000000,
00377     PPC_STFD    = 0xd8000000,
00378     PPC_STFDU   = 0xdc000000,
00379     PPC_LD      = 0xe8000000,
00380     PPC_LDU     = 0xe8000001,
00381     PPC_LWA     = 0xe8000002,
00382     PPC_FDIVS   = 0xec000024,
00383     PPC_FSUBS   = 0xec000028,
00384     PPC_FADDS   = 0xec00002a,
00385 //------------
00386     PPC_FSQRTS  = 0xec000000,
00387     PPC_FRES    = 0xec000000,
00388     PPC_FMULS   = 0xec000032,
00389     PPC_FMSUBS  = 0xec000000,
00390     PPC_FMADDS  = 0xec000000,
00391     PPC_FNMSUBS = 0xec000000,
00392     PPC_FNMADDS = 0xec000000,
00393     PPC_STD     = 0xf8000000,
00394     PPC_STDU    = 0xf8000001,
00395     PPC_FCMPU   = 0xfc000000,
00396     PPC_FRSP    = 0xfc000018,
00397     PPC_FCTIW   = 0xfc000000,
00398     PPC_FCTIWZ  = 0xfc00001e,
00399     PPC_FDIV    = 0xfc000000,
00400     PPC_FSUB    = 0xfc000028,
00401     PPC_FADD    = 0xfc000000,
00402     PPC_FSQRT   = 0xfc000000,
00403     PPC_FSEL    = 0xfc000000,
00404     PPC_FMUL    = 0xfc000000,
00405     PPC_FRSQRTE = 0xfc000000,
00406     PPC_FMSUB   = 0xfc000000,
00407     PPC_FMADD   = 0xfc000000,
00408     PPC_FNMSUB  = 0xfc000000,
00409     PPC_FNMADD  = 0xfc000000,
00410     PPC_FCMPO   = 0xfc000000,
00411     PPC_MTFSB1  = 0xfc000000,
00412     PPC_FNEG    = 0xfc000050,
00413     PPC_MCRFS   = 0xfc000000,
00414     PPC_MTFSB0  = 0xfc000000,
00415     PPC_FMR     = 0xfc000000,
00416     PPC_MTFSFI  = 0xfc000000,
00417     PPC_FNABS   = 0xfc000000,
00418     PPC_FABS    = 0xfc000000,
00419 //------------
00420     PPC_MFFS    = 0xfc000000,
00421     PPC_MTFSF   = 0xfc000000,
00422     PPC_FCTID   = 0xfc000000,
00423     PPC_FCTIDZ  = 0xfc000000,
00424     PPC_FCFID   = 0xfc000000
00425     
00426 } ppcOpcodes_t;
00427 
00428 
00429 // the newly generated code
00430 static  unsigned    *buf;
00431 static  int     compiledOfs;    // in dwords
00432 static int pass;
00433 
00434 // fromt the original bytecode
00435 static  byte    *code;
00436 static  int     pc;
00437 
00438 void AsmCall( void );
00439 
00440 double  itofConvert[2];
00441 
00442 static int  Constant4( void ) {
00443     int     v;
00444 
00445     v = code[pc] | (code[pc+1]<<8) | (code[pc+2]<<16) | (code[pc+3]<<24);
00446     pc += 4;
00447     return v;
00448 }
00449 
00450 static int  Constant1( void ) {
00451     int     v;
00452 
00453     v = code[pc];
00454     pc += 1;
00455     return v;
00456 }
00457 
00458 static void Emit4( char *opname, int i ) {
00459     #if DEBUG_VM
00460     if(pass == 1)
00461         printf("\t\t\t%p %s\t%08lx\n",&buf[compiledOfs],opname,i&0x3ffffff);
00462     #endif
00463     buf[ compiledOfs ] = i;
00464     compiledOfs++;
00465 }
00466 
00467 static void Inst( char *opname, int opcode, int destReg, int aReg, int bReg ) {
00468     unsigned        r;
00469 
00470     #if DEBUG_VM
00471     if(pass == 1)
00472         printf("\t\t\t%p %s\tr%d,r%d,r%d\n",&buf[compiledOfs],opname,destReg,aReg,bReg);
00473     #endif
00474     r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) ;
00475     buf[ compiledOfs ] = r;
00476     compiledOfs++;
00477 }
00478 
00479 static void Inst4( char *opname, int opcode, int destReg, int aReg, int bReg, int cReg ) {
00480     unsigned        r;
00481 
00482     #if DEBUG_VM
00483     if(pass == 1)
00484         printf("\t\t\t%p %s\tr%d,r%d,r%d,r%d\n",&buf[compiledOfs],opname,destReg,aReg,bReg,cReg);
00485     #endif
00486     r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) | ( cReg << 6 );
00487     buf[ compiledOfs ] = r;
00488     compiledOfs++;
00489 }
00490 
00491 static void InstImm( char *opname, int opcode, int destReg, int aReg, int immediate ) {
00492     unsigned        r;
00493     
00494     if ( immediate > 32767 || immediate < -32768 ) {
00495         Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range, opcode %x,%d,%d", immediate, opcode, destReg, aReg );
00496     }
00497     #if DEBUG_VM
00498     if(pass == 1)
00499         printf("\t\t\t%p %s\tr%d,r%d,0x%x\n",&buf[compiledOfs],opname,destReg,aReg,immediate);
00500     #endif
00501     r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff );
00502     buf[ compiledOfs ] = r;
00503     compiledOfs++;
00504 }
00505 
00506 static void InstImmU( char *opname, int opcode, int destReg, int aReg, int immediate ) {
00507     unsigned        r;
00508     
00509     if ( immediate > 0xffff || immediate < 0 ) {
00510         Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range", immediate );
00511     }
00512     #if DEBUG_VM
00513     if(pass == 1)
00514         printf("\t\t\t%p %s\tr%d,r%d,0x%x\n",&buf[compiledOfs],opname,destReg,aReg,immediate);
00515     #endif
00516     r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff );
00517     buf[ compiledOfs ] = r;
00518     compiledOfs++;
00519 }
00520 
00521 static int pop0, pop1, oc0, oc1;
00522 static vm_t *tvm;
00523 static int instruction;
00524 static byte *jused;
00525 
00526 static void ltop() {
00527 //    if (rtopped == qfalse) {
00528 //  InstImm( PPC_LWZ, R_TOP, R_OPSTACK, 0 );        // get value from opstack
00529 //    }
00530 }
00531 
00532 static void ltopandsecond() {
00533 #if 0
00534     if (pass>=0 && buf[compiledOfs-1] == (PPC_STWU |  R_TOP<<21 | R_OPSTACK<<16 | 4 ) && jused[instruction]==0 ) {
00535     compiledOfs--;
00536     if (!pass) {
00537         tvm->instructionPointers[instruction] = compiledOfs * 4;
00538     }
00539     InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack
00540     InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
00541     } else if (pass>=0 && buf[compiledOfs-1] == (PPC_STW |  R_TOP<<21 | R_OPSTACK<<16 | 0 )  && jused[instruction]==0 ) {
00542     compiledOfs--;
00543     if (!pass) {
00544         tvm->instructionPointers[instruction] = compiledOfs * 4;
00545     }
00546     InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, -4 );    // get value from opstack
00547     InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 );
00548     } else {
00549     ltop();     // get value from opstack
00550     InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, -4 );    // get value from opstack
00551     InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 );
00552     }
00553     rtopped = qfalse;
00554 #endif
00555 }
00556 
00557 static void spillOpStack(int depth)
00558 {
00559     // Store out each register on the operand stack to it's correct location.
00560     int i;
00561     
00562     for(i = 0; i < depth; i++)
00563     {
00564         assert(opStackRegType[i]);
00565         assert(opStackRegType[i] == 1);
00566         switch(opStackRegType[i])
00567         {
00568             case 1: // Integer register
00569                 InstImm( "stw", PPC_STW, opStackIntRegisters[i], R_OPSTACK, i*4+4);
00570                 break;
00571             case 2: // Float register
00572                 InstImm( "stfs", PPC_STFS, opStackFloatRegisters[i], R_OPSTACK, i*4+4);
00573                 break;
00574         }
00575         opStackRegType[i] = 0;
00576     }
00577 }
00578 
00579 static void loadOpStack(int depth)
00580 {
00581     // Back off operand stack pointer and reload all operands.
00582 //  InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, -(depth)*4 );
00583 
00584     int i;
00585     
00586     for(i = 0; i < depth; i++)
00587     {
00588         assert(opStackRegType[i] == 0);
00589         // For now we're stuck reloading everything as an integer.
00590         opStackLoadInstructionAddr[i] = &buf[compiledOfs];
00591         InstImm( "lwz", PPC_LWZ, opStackIntRegisters[i], R_OPSTACK, i*4+4);
00592         opStackRegType[i] = 1;
00593     }   
00594 }
00595 
00596 static void makeInteger(int depth)
00597 {
00598     // This should really never be necessary...
00599     assert(opStackRegType[depth] == 1);
00600     //assert(opStackRegType[depth] == 2);
00601     if(opStackRegType[depth] == 2)
00602     {
00603         unsigned instruction;
00604         assert(opStackLoadInstructionAddr[depth]);
00605         
00606         printf("patching float load at %p to int load\n",opStackLoadInstructionAddr[depth]);
00607         // Repatch load instruction to use LFS instead of LWZ
00608         instruction = *opStackLoadInstructionAddr[depth];
00609         instruction &= ~PPC_LFSX;
00610         instruction |=  PPC_LWZX;
00611         *opStackLoadInstructionAddr[depth] = instruction;
00612         opStackLoadInstructionAddr[depth] = 0;
00613         opStackRegType[depth] = 1;
00614         #if 0
00615         InstImm( "stfs", PPC_STFS, opStackFloatRegisters[depth], R_OPSTACK, depth*4+4);
00616         // For XXX make sure we force enough NOPs to get the load into
00617         // another dispatch group to avoid pipeline flush.
00618         Inst( "ori", PPC_ORI,  0, 0, 0 );
00619         Inst( "ori", PPC_ORI,  0, 0, 0 );
00620         Inst( "ori", PPC_ORI,  0, 0, 0 );
00621         Inst( "ori", PPC_ORI,  0, 0, 0 );
00622         InstImm( "lwz", PPC_LWZ, opStackIntRegisters[depth], R_OPSTACK, depth*4+4);
00623         opStackRegType[depth] = 1;
00624         #endif
00625     }
00626 }
00627 
00628 static void makeFloat(int depth)
00629 {
00630     //assert(opStackRegType[depth] == 1);
00631     if(opStackRegType[depth] == 1)
00632     {
00633         unsigned instruction;
00634         unsigned destReg, aReg, bReg, imm;
00635         
00636         if(opStackLoadInstructionAddr[depth])
00637         {
00638             // Repatch load instruction to use LFS instead of LWZ
00639             instruction = *opStackLoadInstructionAddr[depth];
00640             // Figure out if it's LWZ or LWZX
00641             if((instruction & 0xfc000000) == PPC_LWZ)
00642             {
00643                 //printf("patching LWZ at %p to LFS at depth %ld\n",opStackLoadInstructionAddr[depth],depth);
00644                 //printf("old instruction: %08lx\n",instruction);
00645                 // Extract registers
00646                 destReg = (instruction >> 21) & 31;
00647                 aReg    = (instruction >> 16) & 31;
00648                 imm     = instruction & 0xffff;
00649                 
00650                 // Calculate correct FP register to use.
00651                 // THIS ASSUMES REGISTER USAGE FOR THE STACK IS n, n+1, n+2, etc!
00652                 //printf("old dest: %ld\n",destReg);
00653                 destReg = (destReg - opStackIntRegisters[0]) + opStackFloatRegisters[0];
00654                 instruction = PPC_LFS | ( destReg << 21 ) | ( aReg << 16 ) | imm ;          
00655                 //printf("new dest: %ld\n",destReg);
00656                 //printf("new instruction: %08lx\n",instruction);
00657             }
00658             else
00659             {
00660                 //printf("patching LWZX at %p to LFSX at depth %ld\n",opStackLoadInstructionAddr[depth],depth);
00661                 //printf("old instruction: %08lx\n",instruction);
00662                 // Extract registers
00663                 destReg = (instruction >> 21) & 31;
00664                 aReg    = (instruction >> 16) & 31;
00665                 bReg    = (instruction >> 11) & 31;
00666                 // Calculate correct FP register to use.
00667                 // THIS ASSUMES REGISTER USAGE FOR THE STACK IS n, n+1, n+2, etc!
00668                 //printf("old dest: %ld\n",destReg);
00669                 destReg = (destReg - opStackIntRegisters[0]) + opStackFloatRegisters[0];
00670                 instruction = PPC_LFSX | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) ;          
00671                 //printf("new dest: %ld\n",destReg);
00672                 //printf("new instruction: %08lx\n",instruction);
00673             }
00674             *opStackLoadInstructionAddr[depth] = instruction;
00675             opStackLoadInstructionAddr[depth] = 0;
00676         }
00677         else
00678         {   
00679             //printf("doing float constant load at %p for depth %ld\n",&buf[compiledOfs],depth);
00680             // It was likely loaded as a constant so we have to save/load it.  A more
00681             // interesting implementation might be to generate code to do a "PC relative"
00682             // load from the VM code region.
00683             InstImm( "stw", PPC_STW, opStackIntRegisters[depth], R_OPSTACK, depth*4+4);
00684             // For XXX make sure we force enough NOPs to get the load into
00685             // another dispatch group to avoid pipeline flush.
00686             Inst( "ori", PPC_ORI,  0, 0, 0 );
00687             Inst( "ori", PPC_ORI,  0, 0, 0 );
00688             Inst( "ori", PPC_ORI,  0, 0, 0 );
00689             Inst( "ori", PPC_ORI,  0, 0, 0 );
00690             InstImm( "lfs", PPC_LFS, opStackFloatRegisters[depth], R_OPSTACK, depth*4+4);
00691         }
00692         opStackRegType[depth] = 2;
00693     }
00694 }
00695 
00696 // TJW: Unused
00697 #if 0
00698 static void fltop() {
00699     if (rtopped == qfalse) {
00700     InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 );        // get value from opstack
00701     }
00702 }
00703 #endif
00704 
00705 #if 0
00706 static void fltopandsecond() {
00707     InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 );        // get value from opstack
00708     InstImm( PPC_LFS, R_SECOND, R_OPSTACK, -4 );    // get value from opstack
00709     InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 );
00710     rtopped = qfalse;
00711     return;
00712 }
00713 #endif
00714 
00715 #define assertInteger(depth)    assert(opStackRegType[depth] == 1)
00716 
00717 /*
00718 =================
00719 VM_Compile
00720 =================
00721 */
00722 void VM_Compile( vm_t *vm, vmHeader_t *header ) {
00723     int     op;
00724     int     maxLength;
00725     int     v;
00726     int     i;
00727         int     opStackDepth;
00728     
00729     int     mainFunction;
00730     
00731     // set up the into-to-float variables
00732     ((int *)itofConvert)[0] = 0x43300000;
00733     ((int *)itofConvert)[1] = 0x80000000;
00734     ((int *)itofConvert)[2] = 0x43300000;
00735 
00736     // allocate a very large temp buffer, we will shrink it later
00737     maxLength = header->codeLength * 8;
00738     buf = Z_Malloc( maxLength );
00739     jused = Z_Malloc(header->instructionCount + 2);
00740     Com_Memset(jused, 0, header->instructionCount+2);
00741     
00742     // compile everything twice, so the second pass will have valid instruction
00743     // pointers for branches
00744     for ( pass = -1 ; pass < 2 ; pass++ ) {
00745 
00746         // translate all instructions
00747         pc = 0;
00748     mainFunction = 0;
00749     opStackDepth = 0;
00750     
00751     pop0 = 343545;
00752     pop1 = 2443545;
00753     oc0 = -2343535;
00754     oc1 = 24353454;
00755     tvm = vm;
00756         code = (byte *)header + header->codeOffset;
00757         compiledOfs = 0;
00758 #ifndef __GNUC__
00759         // metrowerks seems to require this header in front of functions
00760         Emit4( (int)(buf+2) );
00761         Emit4( 0 );
00762 #endif
00763 
00764     for ( instruction = 0 ; instruction < header->instructionCount ; instruction++ ) {
00765             if ( compiledOfs*4 > maxLength - 16 ) {
00766                 Com_Error( ERR_DROP, "VM_Compile: maxLength exceeded" );
00767             }
00768 
00769             op = code[ pc ];
00770             if ( !pass ) {
00771                 vm->instructionPointers[ instruction ] = compiledOfs * 4;
00772             }
00773             pc++;
00774             switch ( op ) {
00775             case 0:
00776                 break;
00777             case OP_BREAK:
00778         #if DEBUG_VM
00779         if(pass == 1)
00780             printf("%08lx BREAK\n",instruction);
00781         #endif
00782                 InstImmU( "addi", PPC_ADDI, R_TOP, 0, 0 );
00783                 InstImm( "lwz", PPC_LWZ, R_TOP, R_TOP, 0 );         // *(int *)0 to crash to debugger
00784                 break;
00785             case OP_ENTER:
00786         opStackDepth = 0;
00787         v = Constant4();
00788         #if DEBUG_VM
00789         if(pass == 1)
00790             printf("%08x ENTER\t%04x\n",instruction,v);
00791         #endif
00792         opStackRegType[opStackDepth] = 0;
00793         mainFunction++;
00794         if(mainFunction == 1)
00795         {
00796             // Main VM entry point is the first thing we compile, so save off operand stack
00797             // registers here.  This avoids issues with trying to trick the native compiler
00798             // into doing it, and properly matches the PowerPC ABI
00799             InstImm( "addi", PPC_ADDI, R_REAL_STACK, R_REAL_STACK, -OP_STACK_MAX_DEPTH*4 ); // sub R_STACK, R_STACK, imm
00800             for(i = 0; i < OP_STACK_MAX_DEPTH; i++)
00801                 InstImm( "stw", PPC_STW, opStackIntRegisters[i], R_REAL_STACK, i*4);
00802         }
00803                 InstImm( "addi", PPC_ADDI, R_STACK, R_STACK, -v );  // sub R_STACK, R_STACK, imm
00804                 break;
00805             case OP_CONST:
00806                 v = Constant4();
00807         #if DEBUG_VM
00808         if(pass == 1)
00809             printf("%08x CONST\t%08x\n",instruction,v);
00810         #endif
00811         opStackLoadInstructionAddr[opStackDepth] = 0;
00812                 if ( v < 32768 && v >= -32768 ) {
00813                     InstImmU( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth], 0, v & 0xffff );
00814                 } else {
00815                     InstImmU( "addis", PPC_ADDIS, opStackIntRegisters[opStackDepth], 0, (v >> 16)&0xffff );
00816                     if ( v & 0xffff ) {
00817                         InstImmU( "ori", PPC_ORI, opStackIntRegisters[opStackDepth], opStackIntRegisters[opStackDepth], v & 0xffff );
00818                     }
00819                 }
00820         opStackRegType[opStackDepth] = 1;
00821         opStackDepth += 1;
00822         if (code[pc] == OP_JUMP) {
00823             jused[v] = 1;
00824         }
00825         break;
00826             case OP_LOCAL:
00827         oc1 = Constant4();
00828         #if DEBUG_VM
00829         if(pass == 1)
00830             printf("%08x LOCAL\t%08x\n",instruction,oc1);
00831         #endif
00832         if (code[pc] == OP_LOAD4 || code[pc] == OP_LOAD2 || code[pc] == OP_LOAD1) {
00833             oc1 &= vm->dataMask;
00834         }
00835                 InstImm( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth], R_STACK, oc1 );
00836         opStackRegType[opStackDepth] = 1;
00837         opStackLoadInstructionAddr[opStackDepth] = 0;
00838         opStackDepth += 1;
00839                 break;
00840             case OP_ARG:
00841         v = Constant1();
00842         #if DEBUG_VM
00843         if(pass == 1)
00844             printf("%08x ARG \t%08x\n",instruction,v);
00845         #endif
00846                 InstImm( "addi", PPC_ADDI, R_EA, R_STACK, v );  // location to put it
00847         if(opStackRegType[opStackDepth-1] == 1)
00848             Inst( "stwx", PPC_STWX, opStackIntRegisters[opStackDepth-1], R_EA, R_MEMBASE );
00849         else
00850             Inst( "stfsx", PPC_STFSX, opStackFloatRegisters[opStackDepth-1], R_EA, R_MEMBASE );
00851         opStackRegType[opStackDepth-1] = 0;
00852         opStackLoadInstructionAddr[opStackDepth-1] = 0;
00853         opStackDepth -= 1;
00854         
00855                 break;
00856             case OP_CALL:
00857         #if DEBUG_VM
00858         if(pass == 1)
00859             printf("%08x CALL\n",instruction);
00860         #endif
00861         assertInteger(opStackDepth-1);
00862         assert(opStackDepth > 0);
00863                 Inst( "mflr", PPC_MFSPR, R_SECOND, 8, 0 );          // move from link register
00864                 InstImm( "stwu", PPC_STWU, R_SECOND, R_REAL_STACK, -16 );   // save off the old return address
00865 
00866         // Spill operand stack registers.
00867         spillOpStack(opStackDepth);
00868         
00869         // We need to leave R_OPSTACK pointing to the top entry on the stack, which is the call address.
00870         // It will be consumed (and R4 decremented) by the AsmCall code.
00871         InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, opStackDepth*4);
00872 
00873                 Inst( "mtctr", PPC_MTSPR, R_ASMCALL, 9, 0 );            // move to count register
00874                 Inst( "bctrl", PPC_BCCTR | 1, 20, 0, 0 );           // jump and link to the count register
00875 
00876         // R4 now points to the top of the operand stack, which has the return value in it.  We want to
00877         // back off the pointer to point to the base of our local operand stack and then reload the stack.
00878         
00879         InstImm("addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, -opStackDepth*4);
00880         
00881         // Reload operand stack.
00882         loadOpStack(opStackDepth);
00883 
00884                 InstImm( "lwz", PPC_LWZ, R_SECOND, R_REAL_STACK, 0 );       // fetch the old return address
00885                 InstImm( "addi", PPC_ADDI, R_REAL_STACK, R_REAL_STACK, 16 );
00886                 Inst( "mtlr", PPC_MTSPR, R_SECOND, 8, 0 );          // move to link register
00887                 break;
00888             case OP_PUSH:
00889         #if DEBUG_VM
00890         if(pass == 1)
00891             printf("%08x PUSH\n",instruction);
00892         #endif
00893         opStackRegType[opStackDepth] = 1;   // Garbage int value.
00894         opStackDepth += 1;
00895                 break;
00896             case OP_POP:
00897         #if DEBUG_VM
00898         if(pass == 1)
00899             printf("%08x POP\n",instruction);
00900         #endif
00901         opStackDepth -= 1;
00902         opStackRegType[opStackDepth] = 0;   // ??
00903         opStackLoadInstructionAddr[opStackDepth-1] = 0;
00904                 break;
00905             case OP_LEAVE:
00906         #if DEBUG_VM
00907         if(pass == 1)
00908             printf("%08x LEAVE\n",instruction);
00909         #endif
00910         assert(opStackDepth == 1);
00911         assert(opStackRegType[0] != 0);
00912         // Save return value onto top of op stack.  We also have to increment R_OPSTACK
00913         switch(opStackRegType[0])
00914         {
00915             case 1: // Integer register
00916                 InstImm( "stw", PPC_STWU, opStackIntRegisters[0], R_OPSTACK, 4);
00917                 break;
00918             case 2: // Float register
00919                 InstImm( "stfs", PPC_STFSU, opStackFloatRegisters[0], R_OPSTACK, 4);
00920                 break;
00921         }
00922                 InstImm( "addi", PPC_ADDI, R_STACK, R_STACK, Constant4() ); // add R_STACK, R_STACK, imm
00923         if(mainFunction == 1)
00924         {
00925             for(i = 0; i < OP_STACK_MAX_DEPTH; i++)
00926                 InstImm( "lwz", PPC_LWZ,  opStackIntRegisters[i], R_REAL_STACK, i*4);
00927             InstImm( "addi", PPC_ADDI, R_REAL_STACK, R_REAL_STACK, OP_STACK_MAX_DEPTH*4 );  
00928         }
00929         opStackDepth--;
00930         opStackRegType[opStackDepth] = 0;
00931         opStackLoadInstructionAddr[opStackDepth] = 0;
00932                 Inst( "blr", PPC_BCLR, 20, 0, 0 );                          // branch unconditionally to link register
00933                 break;
00934             case OP_LOAD4:
00935         #if DEBUG_VM
00936         if(pass == 1)
00937             printf("%08x LOAD4\n",instruction);
00938         #endif
00939         // We should try to figure out whether to use LWZX or LFSX based
00940         // on some kind of code analysis after subsequent passes.  I think what
00941         // we could do is store the compiled load instruction address along with
00942         // the register type.  When we hit the first mismatched operator, we go back
00943         // and patch the load.  Since LCC's operand stack should be at 0 depth by the
00944         // time we hit a branch, this should work fairly well.  FIXME FIXME FIXME.
00945         assertInteger(opStackDepth-1);
00946         opStackLoadInstructionAddr[opStackDepth-1] = &buf[ compiledOfs ];
00947                 Inst( "lwzx", PPC_LWZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );// load from memory base
00948         opStackRegType[opStackDepth-1] = 1;
00949                 break;
00950             case OP_LOAD2:
00951         #if DEBUG_VM
00952         if(pass == 1)
00953             printf("%08x LOAD2\n",instruction);
00954         #endif
00955         assertInteger(opStackDepth-1);
00956         opStackLoadInstructionAddr[opStackDepth-1] = 0;
00957                 Inst( "lhzx", PPC_LHZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );// load from memory base
00958         opStackRegType[opStackDepth-1] = 1;
00959                 break;
00960             case OP_LOAD1:
00961         #if DEBUG_VM
00962         if(pass == 1)
00963             printf("%08x LOAD1\n",instruction);
00964         #endif
00965         assertInteger(opStackDepth-1);
00966         opStackLoadInstructionAddr[opStackDepth-1] = 0;
00967                 Inst( "lbzx", PPC_LBZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );// load from memory base
00968         opStackRegType[opStackDepth-1] = 1;
00969                 break;
00970             case OP_STORE4:
00971         #if DEBUG_VM
00972         if(pass == 1)
00973             printf("%08x STORE4\n",instruction);
00974         #endif
00975         assertInteger(opStackDepth-2);
00976         if(opStackRegType[opStackDepth-1] == 1)
00977             Inst( "stwx", PPC_STWX, opStackIntRegisters[opStackDepth-1], 
00978                     opStackIntRegisters[opStackDepth-2], R_MEMBASE );       // store from memory base
00979         else
00980             Inst( "stfsx", PPC_STFSX, opStackFloatRegisters[opStackDepth-1], 
00981                     opStackIntRegisters[opStackDepth-2], R_MEMBASE );       // store from memory base
00982         opStackRegType[opStackDepth-1] = 0;
00983         opStackRegType[opStackDepth-2] = 0;
00984         opStackLoadInstructionAddr[opStackDepth-1] = 0;
00985         opStackLoadInstructionAddr[opStackDepth-2] = 0;
00986         opStackDepth -= 2;
00987                 break;
00988             case OP_STORE2:
00989         #if DEBUG_VM
00990         if(pass == 1)
00991             printf("%08x STORE2\n",instruction);
00992         #endif
00993         assertInteger(opStackDepth-1);
00994         assertInteger(opStackDepth-2);
00995                 Inst( "sthx", PPC_STHX, opStackIntRegisters[opStackDepth-1],
00996                 opStackIntRegisters[opStackDepth-2], R_MEMBASE );       // store from memory base
00997         opStackRegType[opStackDepth-1] = 0;
00998         opStackRegType[opStackDepth-2] = 0;
00999         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01000         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01001         opStackDepth -= 2;
01002                 break;
01003             case OP_STORE1:
01004         #if DEBUG_VM
01005         if(pass == 1)
01006             printf("%08x STORE1\n",instruction);
01007         #endif
01008         assertInteger(opStackDepth-1);
01009         assertInteger(opStackDepth-2);
01010                 Inst( "stbx", PPC_STBX, opStackIntRegisters[opStackDepth-1],
01011                 opStackIntRegisters[opStackDepth-2], R_MEMBASE );       // store from memory base
01012         opStackRegType[opStackDepth-1] = 0;
01013         opStackRegType[opStackDepth-2] = 0;
01014         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01015         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01016         opStackDepth -= 2;
01017                 break;
01018 
01019             case OP_EQ:
01020         #if DEBUG_VM
01021         if(pass == 1)
01022             printf("%08x EQ\n",instruction);
01023         #endif
01024         assertInteger(opStackDepth-1);
01025         assertInteger(opStackDepth-2);
01026                 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01027         opStackRegType[opStackDepth-1] = 0;
01028         opStackRegType[opStackDepth-2] = 0;
01029         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01030         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01031         opStackDepth -= 2;
01032                 i = Constant4();
01033                 jused[i] = 1;
01034                 InstImm( "bc", PPC_BC, 4, 2, 8 );
01035                 if ( pass==1 ) {
01036                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];                    
01037                 } else {
01038                     v = 0;             
01039                 }
01040                 Emit4("b", PPC_B | (v&0x3ffffff) );
01041                 break;
01042             case OP_NE:
01043         #if DEBUG_VM
01044         if(pass == 1)
01045             printf("%08x NE\n",instruction);
01046         #endif
01047         assertInteger(opStackDepth-1);
01048         assertInteger(opStackDepth-2);
01049                 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01050         opStackRegType[opStackDepth-1] = 0;
01051         opStackRegType[opStackDepth-2] = 0;
01052         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01053         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01054         opStackDepth -= 2;
01055                 i = Constant4();
01056                 jused[i] = 1;
01057                 InstImm( "bc", PPC_BC, 12, 2, 8 );
01058                 if ( pass==1 ) {
01059                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];                    
01060                 } else {
01061                     v = 0;
01062                 }
01063                 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01064 //                InstImm( "bc", PPC_BC, 4, 2, v );
01065 
01066                 break;
01067             case OP_LTI:
01068         #if DEBUG_VM
01069         if(pass == 1)
01070         printf("%08x LTI\n",instruction);
01071         #endif
01072         assertInteger(opStackDepth-1);
01073         assertInteger(opStackDepth-2);
01074                 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01075         opStackRegType[opStackDepth-1] = 0;
01076         opStackRegType[opStackDepth-2] = 0;
01077         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01078         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01079         opStackDepth -= 2;
01080                 i = Constant4();
01081                 jused[i] = 1;
01082                 InstImm( "bc", PPC_BC, 4, 0, 8 );
01083                 if ( pass==1 ) {
01084                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01085                 } else {
01086                     v = 0;
01087                 }
01088                 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01089 //                InstImm( "bc", PPC_BC, 12, 0, v );
01090                 break;
01091             case OP_LEI:
01092         #if DEBUG_VM
01093         if(pass == 1)
01094         printf("%08x LEI\n",instruction);
01095         #endif
01096         assertInteger(opStackDepth-1);
01097         assertInteger(opStackDepth-2);
01098                 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01099         opStackRegType[opStackDepth-1] = 0;
01100         opStackRegType[opStackDepth-2] = 0;
01101         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01102         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01103         opStackDepth -= 2;
01104                 i = Constant4();
01105                 jused[i] = 1;
01106                 InstImm( "bc", PPC_BC, 12, 1, 8 );
01107                 if ( pass==1 ) {
01108                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01109                 } else {
01110                     v = 0;
01111                 }
01112                 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01113 //                InstImm( "bc", PPC_BC, 4, 1, v );
01114                 break;
01115             case OP_GTI:
01116         #if DEBUG_VM
01117         if(pass == 1)
01118         printf("%08x GTI\n",instruction);
01119         #endif
01120         assertInteger(opStackDepth-1);
01121         assertInteger(opStackDepth-2);
01122                 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01123         opStackRegType[opStackDepth-1] = 0;
01124         opStackRegType[opStackDepth-2] = 0;
01125         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01126         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01127         opStackDepth -= 2;
01128                 i = Constant4();
01129                 jused[i] = 1;
01130                 InstImm( "bc", PPC_BC, 4, 1, 8 );
01131                 if ( pass==1 ) {
01132                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01133                 } else {
01134                     v = 0;
01135                 }
01136                 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01137 //                InstImm( "bc", PPC_BC, 12, 1, v );
01138                 break;
01139             case OP_GEI:
01140         #if DEBUG_VM
01141         if(pass == 1)
01142         printf("%08x GEI\n",instruction);
01143         #endif
01144         assertInteger(opStackDepth-1);
01145         assertInteger(opStackDepth-2);
01146                 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01147         opStackRegType[opStackDepth-1] = 0;
01148         opStackRegType[opStackDepth-2] = 0;
01149         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01150         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01151         opStackDepth -= 2;
01152                 i = Constant4();
01153                 jused[i] = 1;
01154                 InstImm( "bc", PPC_BC, 12, 0, 8 );
01155                 if ( pass==1 ) {
01156                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01157                 } else {
01158                     v = 0;
01159                 }
01160                 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01161 //                InstImm( "bc", PPC_BC, 4, 0, v );
01162                 break;
01163             case OP_LTU:
01164         #if DEBUG_VM
01165         if(pass == 1)
01166         printf("%08x LTU\n",instruction);
01167         #endif
01168         assertInteger(opStackDepth-1);
01169         assertInteger(opStackDepth-2);
01170                 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01171         opStackRegType[opStackDepth-1] = 0;
01172         opStackRegType[opStackDepth-2] = 0;
01173         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01174         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01175         opStackDepth -= 2;
01176                 i = Constant4();
01177         jused[i] = 1;
01178                 InstImm( "bc", PPC_BC, 4, 0, 8 );
01179                 if ( pass==1 ) {
01180                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01181                 } else {
01182                     v = 0;
01183                 }
01184                 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01185 //                InstImm( "bc", PPC_BC, 12, 0, v );
01186                 break;
01187             case OP_LEU:
01188         #if DEBUG_VM
01189         if(pass == 1)
01190         printf("%08x LEU\n",instruction);
01191         #endif
01192         assertInteger(opStackDepth-1);
01193         assertInteger(opStackDepth-2);
01194                 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01195         opStackRegType[opStackDepth-1] = 0;
01196         opStackRegType[opStackDepth-2] = 0;
01197         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01198         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01199         opStackDepth -= 2;
01200                 i = Constant4();
01201         jused[i] = 1;
01202                 InstImm( "bc", PPC_BC, 12, 1, 8 );
01203                 if ( pass==1 ) {
01204                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01205                 } else {
01206                     v = 0;
01207                 }
01208                 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01209 //                InstImm( "bc", PPC_BC, 4, 1, v );
01210                 break;
01211             case OP_GTU:
01212         #if DEBUG_VM
01213         if(pass == 1)
01214         printf("%08x GTU\n",instruction);
01215         #endif
01216         assertInteger(opStackDepth-1);
01217         assertInteger(opStackDepth-2);
01218                 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01219         opStackRegType[opStackDepth-1] = 0;
01220         opStackRegType[opStackDepth-2] = 0;
01221         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01222         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01223         opStackDepth -= 2;
01224                 i = Constant4();
01225         jused[i] = 1;
01226                 InstImm( "bc", PPC_BC, 4, 1, 8 );
01227                 if ( pass==1 ) {
01228                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01229                 } else {
01230                     v = 0;
01231                 }
01232                 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01233 //                InstImm( "bc", PPC_BC, 12, 1, v );
01234                 break;
01235             case OP_GEU:
01236         #if DEBUG_VM
01237         if(pass == 1)
01238         printf("%08x GEU\n",instruction);
01239         #endif
01240         assertInteger(opStackDepth-1);
01241         assertInteger(opStackDepth-2);
01242                 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01243         opStackRegType[opStackDepth-1] = 0;
01244         opStackRegType[opStackDepth-2] = 0;
01245         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01246         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01247         opStackDepth -= 2;
01248                 i = Constant4();
01249         jused[i] = 1;
01250                 InstImm( "bc", PPC_BC, 12, 0, 8 );
01251                 if ( pass==1 ) {
01252                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01253                 } else {
01254                     v = 0;
01255                 }
01256                 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01257 //                InstImm( "bc", PPC_BC, 4, 0, v );
01258                 break;
01259                 
01260             case OP_EQF:
01261         #if DEBUG_VM
01262         if(pass == 1)
01263         printf("%08x EQF\n",instruction);
01264         #endif
01265         makeFloat(opStackDepth-1);
01266         makeFloat(opStackDepth-2);
01267                 Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
01268         opStackRegType[opStackDepth-1] = 0;
01269         opStackRegType[opStackDepth-2] = 0;
01270         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01271         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01272         opStackDepth -= 2;
01273                 i = Constant4();
01274         jused[i] = 1;
01275                 InstImm( "bc", PPC_BC, 4, 2, 8 );
01276                 if ( pass==1 ) {
01277                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01278                 } else {
01279                     v = 0;
01280                 }
01281                 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01282 //                InstImm( "bc", PPC_BC, 12, 2, v );
01283                 break;          
01284             case OP_NEF:
01285         #if DEBUG_VM
01286         if(pass == 1)
01287         printf("%08x NEF\n",instruction);
01288         #endif
01289         makeFloat(opStackDepth-1);
01290         makeFloat(opStackDepth-2);
01291                 Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
01292         opStackRegType[opStackDepth-1] = 0;
01293         opStackRegType[opStackDepth-2] = 0;
01294         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01295         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01296         opStackDepth -= 2;
01297                 i = Constant4();
01298         jused[i] = 1;
01299                 InstImm( "bc", PPC_BC, 12, 2, 8 );
01300                 if ( pass==1 ) {
01301                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01302                 } else {
01303                     v = 0;
01304                 }
01305                 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01306 //                InstImm( "bc", PPC_BC, 4, 2, v );
01307                 break;          
01308             case OP_LTF:
01309         #if DEBUG_VM
01310         if(pass == 1)
01311         printf("%08x LTF\n",instruction);
01312         #endif
01313         makeFloat(opStackDepth-1);
01314         makeFloat(opStackDepth-2);
01315                 Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
01316         opStackRegType[opStackDepth-1] = 0;
01317         opStackRegType[opStackDepth-2] = 0;
01318         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01319         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01320         opStackDepth -= 2;
01321                 i = Constant4();
01322         jused[i] = 1;
01323                 InstImm( "bc", PPC_BC, 4, 0, 8 );
01324                 if ( pass==1 ) {
01325                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01326                 } else {
01327                     v = 0;
01328                 }
01329                 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01330 //                InstImm( "bc", PPC_BC, 12, 0, v );
01331                 break;          
01332             case OP_LEF:
01333         #if DEBUG_VM
01334         if(pass == 1)
01335         printf("%08x LEF\n",instruction);
01336         #endif
01337         makeFloat(opStackDepth-1);
01338         makeFloat(opStackDepth-2);
01339                 Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
01340         opStackRegType[opStackDepth-1] = 0;
01341         opStackRegType[opStackDepth-2] = 0;
01342         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01343         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01344         opStackDepth -= 2;
01345                 i = Constant4();
01346         jused[i] = 1;
01347                 InstImm( "bc", PPC_BC, 12, 1, 8 );
01348                 if ( pass==1 ) {
01349                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01350                 } else {
01351                     v = 0;
01352                 }
01353                 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01354 //                InstImm( "bc", PPC_BC, 4, 1, v );
01355                 break;          
01356             case OP_GTF:
01357         #if DEBUG_VM
01358         if(pass == 1)
01359         printf("%08x GTF\n",instruction);
01360         #endif
01361         makeFloat(opStackDepth-1);
01362         makeFloat(opStackDepth-2);
01363                 Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
01364         opStackRegType[opStackDepth-1] = 0;
01365         opStackRegType[opStackDepth-2] = 0;
01366         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01367         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01368         opStackDepth -= 2;
01369                 i = Constant4();
01370         jused[i] = 1;
01371                 InstImm( "bc", PPC_BC, 4, 1, 8 );
01372                 if ( pass==1 ) {
01373                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01374                 } else {
01375                     v = 0;
01376                 }
01377                 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01378 //                InstImm( "bc", PPC_BC, 12, 1, v );
01379                 break;          
01380             case OP_GEF:
01381         #if DEBUG_VM
01382         if(pass == 1)
01383         printf("%08x GEF\n",instruction);
01384         #endif
01385         makeFloat(opStackDepth-1);
01386         makeFloat(opStackDepth-2);
01387                 Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
01388         opStackRegType[opStackDepth-1] = 0;
01389         opStackRegType[opStackDepth-2] = 0;
01390         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01391         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01392         opStackDepth -= 2;
01393                 i = Constant4();
01394         jused[i] = 1;
01395                 InstImm( "bc", PPC_BC, 12, 0, 8 );
01396                 if ( pass==1 ) {
01397                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01398                 } else {
01399                     v = 0;
01400                 }
01401                 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01402 //                InstImm( "bc", PPC_BC, 4, 0, v );
01403                 break;
01404 
01405             case OP_NEGI:
01406         #if DEBUG_VM
01407         if(pass == 1)
01408         printf("%08x NEGI\n",instruction);
01409         #endif
01410         assertInteger(opStackDepth-1);
01411                 InstImm( "subfic", PPC_SUBFIC, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0 );
01412         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01413                 break;
01414             case OP_ADD:
01415         #if DEBUG_VM
01416         if(pass == 1)
01417         printf("%08x ADD\n",instruction);
01418         #endif
01419         assertInteger(opStackDepth-1);
01420         assertInteger(opStackDepth-2);
01421                 Inst( "add", PPC_ADD, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-2] );
01422         opStackRegType[opStackDepth-1] = 0;
01423         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01424         opStackDepth -= 1;
01425                 break;
01426             case OP_SUB:
01427         #if DEBUG_VM
01428         if(pass == 1)
01429         printf("%08x SUB\n",instruction);
01430         #endif
01431         assertInteger(opStackDepth-1);
01432         assertInteger(opStackDepth-2);
01433                 Inst( "subf", PPC_SUBF, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-2] );
01434         opStackRegType[opStackDepth-1] = 0;
01435         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01436         opStackDepth -= 1;
01437                 break;
01438             case OP_DIVI:
01439         #if DEBUG_VM
01440         if(pass == 1)
01441         printf("%08x DIVI\n",instruction);
01442         #endif
01443         assertInteger(opStackDepth-1);
01444         assertInteger(opStackDepth-2);
01445                 Inst( "divw", PPC_DIVW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01446         opStackRegType[opStackDepth-1] = 0;
01447         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01448         opStackDepth -= 1;
01449                 break;
01450             case OP_DIVU:
01451         #if DEBUG_VM
01452         if(pass == 1)
01453         printf("%08x DIVU\n",instruction);
01454         #endif
01455         assertInteger(opStackDepth-1);
01456         assertInteger(opStackDepth-2);
01457                 Inst( "divwu", PPC_DIVWU, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01458         opStackRegType[opStackDepth-1] = 0;
01459         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01460         opStackDepth -= 1;
01461                 break;
01462             case OP_MODI:
01463         #if DEBUG_VM
01464         if(pass == 1)
01465         printf("%08x MODI\n",instruction);
01466         #endif
01467         assertInteger(opStackDepth-1);
01468         assertInteger(opStackDepth-2);
01469                 Inst( "divw", PPC_DIVW, R_EA, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01470                 Inst( "mullw", PPC_MULLW, R_EA, opStackIntRegisters[opStackDepth-1], R_EA );
01471                 Inst( "subf", PPC_SUBF, opStackIntRegisters[opStackDepth-2], R_EA, opStackIntRegisters[opStackDepth-2] );
01472         opStackRegType[opStackDepth-1] = 0;
01473         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01474         opStackDepth -= 1;
01475                 break;
01476             case OP_MODU:
01477         #if DEBUG_VM
01478         if(pass == 1)
01479         printf("%08x MODU\n",instruction);
01480         #endif
01481         assertInteger(opStackDepth-1);
01482         assertInteger(opStackDepth-2);
01483                 Inst( "divwu", PPC_DIVWU, R_EA, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01484                 Inst( "mullw", PPC_MULLW, R_EA, opStackIntRegisters[opStackDepth-1], R_EA );
01485                 Inst( "subf", PPC_SUBF, opStackIntRegisters[opStackDepth-2], R_EA, opStackIntRegisters[opStackDepth-2] );
01486         opStackRegType[opStackDepth-1] = 0;
01487         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01488         opStackDepth -= 1;
01489                 break;
01490             case OP_MULI:
01491             case OP_MULU:
01492         #if DEBUG_VM
01493         if(pass == 1)
01494         printf("%08x MULI\n",instruction);
01495         #endif
01496         assertInteger(opStackDepth-1);
01497         assertInteger(opStackDepth-2);
01498                 Inst( "mullw", PPC_MULLW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-2] );
01499         opStackRegType[opStackDepth-1] = 0;
01500         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01501         opStackDepth -= 1;
01502                 break;
01503             case OP_BAND:
01504         #if DEBUG_VM
01505         if(pass == 1)
01506         printf("%08x BAND\n",instruction);
01507         #endif
01508         assertInteger(opStackDepth-1);
01509         assertInteger(opStackDepth-2);
01510                 Inst( "and", PPC_AND, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01511         opStackRegType[opStackDepth-1] = 0;
01512         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01513         opStackDepth -= 1;
01514                 break;
01515             case OP_BOR:
01516         #if DEBUG_VM
01517         if(pass == 1)
01518         printf("%08x BOR\n",instruction);
01519         #endif
01520         assertInteger(opStackDepth-1);
01521         assertInteger(opStackDepth-2);
01522                 Inst( "or", PPC_OR, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01523         opStackRegType[opStackDepth-1] = 0;
01524         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01525         opStackDepth -= 1;
01526                 break;
01527             case OP_BXOR:
01528         #if DEBUG_VM
01529         if(pass == 1)
01530         printf("%08x BXOR\n",instruction);
01531         #endif
01532         assertInteger(opStackDepth-1);
01533         assertInteger(opStackDepth-2);
01534                 Inst( "xor", PPC_XOR, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01535         opStackRegType[opStackDepth-1] = 0;
01536         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01537         opStackDepth -= 1;
01538                 break;
01539             case OP_BCOM:
01540         #if DEBUG_VM
01541         if(pass == 1)
01542         printf("%08x BCOM\n",instruction);
01543         #endif
01544         assertInteger(opStackDepth-1);
01545                 Inst( "nor", PPC_NOR, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1] );
01546         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01547                 break;
01548             case OP_LSH:
01549         #if DEBUG_VM
01550         if(pass == 1)
01551         printf("%08x LSH\n",instruction);
01552         #endif
01553         assertInteger(opStackDepth-1);
01554         assertInteger(opStackDepth-2);
01555                 Inst( "slw", PPC_SLW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01556         opStackRegType[opStackDepth-1] = 0;
01557         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01558         opStackDepth -= 1;
01559                 break;
01560             case OP_RSHI:
01561         #if DEBUG_VM
01562         if(pass == 1)
01563         printf("%08x RSHI\n",instruction);
01564         #endif
01565         assertInteger(opStackDepth-1);
01566         assertInteger(opStackDepth-2);
01567                 Inst( "sraw", PPC_SRAW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01568         opStackRegType[opStackDepth-1] = 0;
01569         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01570         opStackDepth -= 1;
01571                 break;
01572             case OP_RSHU:
01573         #if DEBUG_VM
01574         if(pass == 1)
01575         printf("%08x RSHU\n",instruction);
01576         #endif
01577         assertInteger(opStackDepth-1);
01578         assertInteger(opStackDepth-2);
01579                 Inst( "srw", PPC_SRW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01580         opStackRegType[opStackDepth-1] = 0;
01581         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01582         opStackDepth -= 1;
01583                 break;
01584 
01585             case OP_NEGF:
01586         #if DEBUG_VM
01587         if(pass == 1)
01588         printf("%08x NEGF\n",instruction);
01589         #endif
01590         makeFloat(opStackDepth-1);
01591                 Inst( "fneg", PPC_FNEG, opStackFloatRegisters[opStackDepth-1], 0, opStackFloatRegisters[opStackDepth-1] );
01592         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01593                 break;
01594             case OP_ADDF:
01595         #if DEBUG_VM
01596         if(pass == 1)
01597         printf("%08x ADDF\n",instruction);
01598         #endif
01599         makeFloat(opStackDepth-1);
01600         makeFloat(opStackDepth-2);
01601                 Inst( "fadds", PPC_FADDS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
01602         opStackRegType[opStackDepth-1] = 0;
01603         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01604         opStackDepth -= 1;
01605                 break;
01606             case OP_SUBF:
01607         #if DEBUG_VM
01608         if(pass == 1)
01609         printf("%08x SUBF\n",instruction);
01610         #endif
01611         makeFloat(opStackDepth-1);
01612         makeFloat(opStackDepth-2);
01613                 Inst( "fsubs", PPC_FSUBS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
01614         opStackRegType[opStackDepth-1] = 0;
01615         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01616         opStackDepth -= 1;
01617                 break;
01618             case OP_DIVF:
01619         #if DEBUG_VM
01620         if(pass == 1)
01621         printf("%08x DIVF\n",instruction);
01622         #endif
01623         makeFloat(opStackDepth-1);
01624         makeFloat(opStackDepth-2);
01625                 Inst( "fdivs", PPC_FDIVS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
01626         opStackRegType[opStackDepth-1] = 0;
01627         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01628         opStackDepth -= 1;
01629                 break;
01630             case OP_MULF:
01631         #if DEBUG_VM
01632         if(pass == 1)
01633         printf("%08x MULF\n",instruction);
01634         #endif
01635         makeFloat(opStackDepth-1);
01636         makeFloat(opStackDepth-2);
01637                 Inst4( "fmuls", PPC_FMULS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], 0, opStackFloatRegisters[opStackDepth-1] );
01638         opStackRegType[opStackDepth-1] = 0;
01639         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01640         opStackDepth -= 1;
01641                 break;
01642 
01643             case OP_CVIF:
01644         #if DEBUG_VM
01645         if(pass == 1)
01646         printf("%08x CVIF\n",instruction);
01647         #endif
01648         assertInteger(opStackDepth-1);
01649         //makeInteger(opStackDepth-1);
01650                 v = (int)&itofConvert;
01651                 InstImmU( "addis", PPC_ADDIS, R_EA, 0, (v >> 16)&0xffff );
01652                 InstImmU( "ori", PPC_ORI, R_EA, R_EA, v & 0xffff );
01653                 InstImmU( "xoris", PPC_XORIS, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0x8000 );
01654                 InstImm( "stw", PPC_STW, opStackIntRegisters[opStackDepth-1], R_EA, 12 );
01655                 InstImm( "lfd", PPC_LFD, opStackFloatRegisters[opStackDepth-1], R_EA, 0 );
01656         Inst( "ori", PPC_ORI, 0, 0, 0);
01657         Inst( "ori", PPC_ORI, 0, 0, 0);
01658         Inst( "ori", PPC_ORI, 0, 0, 0);
01659                 InstImm( "lfd", PPC_LFD, 13, R_EA, 8 );
01660                 Inst( "fsub", PPC_FSUB, opStackFloatRegisters[opStackDepth-1], 13, opStackFloatRegisters[opStackDepth-1] );
01661         opStackRegType[opStackDepth-1] = 2;
01662         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01663     //            Inst( PPC_FRSP, R_TOP, 0, R_TOP );
01664                 break;
01665             case OP_CVFI:
01666         #if DEBUG_VM
01667         if(pass == 1)
01668         printf("%08x CVFI\n",instruction);
01669         #endif
01670         makeFloat(opStackDepth-1);
01671 
01672         InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, opStackDepth*4);
01673 
01674                 Inst( "fctiwz", PPC_FCTIWZ, opStackFloatRegisters[opStackDepth-1], 0, opStackFloatRegisters[opStackDepth-1] );
01675                 Inst( "stfiwx", PPC_STFIWX, opStackFloatRegisters[opStackDepth-1], 0, R_OPSTACK );      // save value to opstack (dummy area now)
01676         Inst( "ori", PPC_ORI, 0, 0, 0);
01677         Inst( "ori", PPC_ORI, 0, 0, 0);
01678         Inst( "ori", PPC_ORI, 0, 0, 0);
01679         Inst( "ori", PPC_ORI, 0, 0, 0);
01680                 InstImm( "lwz", PPC_LWZ, opStackIntRegisters[opStackDepth-1], R_OPSTACK, 0 );
01681         
01682         InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, -opStackDepth*4);
01683         
01684         opStackRegType[opStackDepth-1] = 1;
01685         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01686                 break;
01687             case OP_SEX8:
01688         #if DEBUG_VM
01689         if(pass == 1)
01690         printf("%08x SEX8\n",instruction);
01691         #endif
01692         assertInteger(opStackDepth-1);
01693                 Inst( "extsb", PPC_EXTSB, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0 );
01694         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01695                 break;
01696             case OP_SEX16:
01697         #if DEBUG_VM
01698         if(pass == 1)
01699         printf("%08x SEX16\n",instruction);
01700         #endif
01701         assertInteger(opStackDepth-1);
01702                 Inst( "extsh", PPC_EXTSH, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0 );
01703         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01704                 break;
01705 
01706             case OP_BLOCK_COPY:
01707                 v = Constant4() >> 2;
01708         #if DEBUG_VM
01709         if(pass == 1)
01710         printf("%08x BLOCK_COPY\t%08lx\n",instruction,v<<2);
01711         #endif
01712         assert(opStackDepth >= 2);
01713         assertInteger(opStackDepth-1);
01714         assertInteger(opStackDepth-2);
01715                 InstImmU( "addi", PPC_ADDI, R_EA, 0, v );               // count
01716                 // FIXME: range check
01717                 Inst( "mtctr", PPC_MTSPR, R_EA, 9, 0 );                 // move to count register
01718 
01719                 Inst( "add", PPC_ADD, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );
01720                 InstImm( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], -4 );
01721                 Inst( "add", PPC_ADD, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], R_MEMBASE );
01722                 InstImm( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], -4 );
01723 
01724                 InstImm( "lwzu", PPC_LWZU, R_EA, opStackIntRegisters[opStackDepth-1], 4 );      // source
01725                 InstImm( "stwu", PPC_STWU, R_EA, opStackIntRegisters[opStackDepth-2], 4 );  // dest
01726                 Inst( "b", PPC_BC | 0xfff8 , 16, 0, 0 );                    // loop
01727         opStackRegType[opStackDepth-1] = 0;
01728         opStackRegType[opStackDepth-2] = 0;
01729         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01730         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01731         opStackDepth -= 2;
01732                 break;
01733 
01734             case OP_JUMP:
01735         #if DEBUG_VM
01736         if(pass == 1)
01737         printf("%08x JUMP\n",instruction);
01738         #endif
01739         assert(opStackDepth == 1);
01740         assertInteger(opStackDepth-1);
01741 
01742                 Inst( "rlwinm", PPC_RLWINM | ( 29 << 1 ), opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 2 );
01743         // FIXME: range check
01744         Inst( "lwzx", PPC_LWZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_INSTRUCTIONS );
01745                 Inst( "mtctr", PPC_MTSPR, opStackIntRegisters[opStackDepth-1], 9, 0 );      // move to count register
01746                 Inst( "bctr", PPC_BCCTR, 20, 0, 0 );        // jump to the count register
01747         opStackRegType[opStackDepth-1] = 0;
01748         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01749         opStackDepth -= 1;
01750                 break;
01751             default:
01752                 Com_Error( ERR_DROP, "VM_CompilePPC: bad opcode %i at instruction %i, offset %i", op, instruction, pc );
01753             }
01754         pop0 = pop1;
01755         pop1 = op;
01756         assert(opStackDepth >= 0);
01757         assert(opStackDepth < OP_STACK_MAX_DEPTH);
01758         
01759         //printf("%4d\t%s\n",opStackDepth,opnames[op]);
01760         }
01761 
01762     Com_Printf( "VM file %s pass %d compiled to %i bytes of code\n", vm->name, (pass+1), compiledOfs*4 );
01763 
01764         if ( pass == 0 ) {
01765         // copy to an exact size buffer on the hunk
01766         vm->codeLength = compiledOfs * 4;
01767         vm->codeBase = Hunk_Alloc( vm->codeLength, h_low );
01768         Com_Memcpy( vm->codeBase, buf, vm->codeLength );
01769         
01770         //printf("codeBase: %p\n",vm->codeBase);
01771         
01772         Z_Free( buf );
01773     
01774         // offset all the instruction pointers for the new location
01775         for ( i = 0 ; i < header->instructionCount ; i++ ) {
01776         vm->instructionPointers[i] += (int)vm->codeBase;
01777         //printf("%08x %08lx\n",i,vm->instructionPointers[i]);
01778         }
01779 
01780         // go back over it in place now to fixup reletive jump targets
01781         buf = (unsigned *)vm->codeBase;
01782     }
01783     }
01784     if(0)
01785     {
01786     char buf[256];
01787     printf("wait..\n");
01788     gets(buf);
01789     }
01790     Z_Free( jused );
01791 }
01792 
01793 /*
01794 ==============
01795 VM_CallCompiled
01796 
01797 This function is called directly by the generated code
01798 ==============
01799 */
01800 int VM_CallCompiled( vm_t *vm, int *args ) {
01801     int     stack[1024];
01802     int     programStack;
01803     int     stackOnEntry;
01804     byte    *image;
01805 
01806     currentVM = vm;
01807 
01808     //printf("VM_CallCompiled: %p   %08lx %08lx %08lx\n",
01809     //  vm, args[0],args[1],args[2]);
01810         
01811     // interpret the code
01812     vm->currentlyInterpreting = qtrue;
01813 
01814     // we might be called recursively, so this might not be the very top
01815     programStack = vm->programStack;
01816     stackOnEntry = programStack;
01817     image = vm->dataBase;
01818     
01819     // set up the stack frame 
01820     programStack -= 48;
01821 
01822     *(int *)&image[ programStack + 44] = args[9];
01823     *(int *)&image[ programStack + 40] = args[8];
01824     *(int *)&image[ programStack + 36] = args[7];
01825     *(int *)&image[ programStack + 32] = args[6];
01826     *(int *)&image[ programStack + 28] = args[5];
01827     *(int *)&image[ programStack + 24] = args[4];
01828     *(int *)&image[ programStack + 20] = args[3];
01829     *(int *)&image[ programStack + 16] = args[2];
01830     *(int *)&image[ programStack + 12] = args[1];
01831     *(int *)&image[ programStack + 8 ] = args[0];
01832     *(int *)&image[ programStack + 4 ] = 0; // return stack
01833     *(int *)&image[ programStack ] = -1;    // will terminate the loop on return
01834 
01835     // Cheesy... manually save registers used by VM call...
01836     // off we go into generated code...
01837     // the PPC calling standard says the parms will all go into R3 - R11, so 
01838     // no special asm code is needed here
01839 #ifdef __GNUC__
01840     ((void(*)(int, int, int, int, int, int, int, int))(vm->codeBase))( 
01841         programStack, (int)&stack, 
01842         (int)image, vm->dataMask, (int)&AsmCall, 
01843         (int)vm->instructionPointers, vm->instructionPointersLength,
01844         (int)vm );
01845 #else
01846     ((void(*)(int, int, int, int, int, int, int, int))(vm->codeBase))( 
01847         programStack, (int)&stack, 
01848         (int)image, vm->dataMask, *(int *)&AsmCall /* skip function pointer header */, 
01849         (int)vm->instructionPointers, vm->instructionPointersLength,
01850         (int)vm );
01851 #endif
01852     vm->programStack = stackOnEntry;
01853 
01854     vm->currentlyInterpreting = qfalse;
01855 
01856     return stack[1];
01857 }
01858 
01859 
01860 /*
01861 ==================
01862 AsmCall
01863 
01864 Put this at end of file because gcc messes up debug line numbers 
01865 ==================
01866 */
01867 #ifdef __GNUC__
01868 
01869 void AsmCall( void ) {
01870 asm (
01871      // pop off the destination instruction
01872 "    lwz        r12,0(r4)   \n" // RG_TOP, 0(RG_OPSTACK)
01873 "    addi   r4,r4,-4        \n" // RG_OPSTACK, RG_OPSTACK, -4 \n"
01874 
01875     // see if it is a system trap
01876 "    cmpwi  r12,0           \n" // RG_TOP, 0 \n"
01877 "    bc     12,0, systemTrap    \n"
01878 
01879     // calling another VM function, so lookup in instructionPointers
01880 "    slwi   r12,r12,2       \n" // RG_TOP,RG_TOP,2
01881                         // FIXME: range check
01882 "    lwzx   r12, r8, r12        \n" // RG_TOP, RG_INSTRUCTIONS(RG_TOP)  
01883 "    mtctr  r12         \n" // RG_TOP
01884 );
01885 
01886 #if defined(MACOS_X) && defined(__OPTIMIZE__)
01887     // On Mac OS X, gcc doesn't push a frame when we are optimized, so trying to tear it down results in grave disorder.
01888 #warning Mac OS X optimization on, not popping GCC AsmCall frame
01889 #else
01890     // Mac OS X Server and unoptimized compiles include a GCC AsmCall frame
01891     asm (
01892 "   lwz     r1,0(r1)    \n" // pop off the GCC AsmCall frame
01893 "   lmw     r30,-8(r1)  \n"
01894 );
01895 #endif
01896 
01897 asm (
01898 "       bcctr   20,0        \n" // when it hits a leave, it will branch to the current link register
01899 
01900     // calling a system trap
01901 "systemTrap:                \n"
01902     // convert to positive system call number
01903 "   subfic  r12,r12,-1      \n"
01904 
01905     // save all our registers, including the current link register
01906 "    mflr   r13         \n" // RG_SECOND        // copy off our link register
01907 "   addi    r1,r1,-92       \n" // required 24 byets of linkage, 32 bytes of parameter, plus our saves
01908 "    stw        r3,56(r1)   \n" // RG_STACK, -36(REAL_STACK)
01909 "    stw        r4,60(r1)   \n" // RG_OPSTACK, 4(RG_REAL_STACK)
01910 "    stw        r5,64(r1)   \n" // RG_MEMBASE, 8(RG_REAL_STACK)
01911 "    stw        r6,68(r1)   \n" // RG_MEMMASK, 12(RG_REAL_STACK)
01912 "    stw        r7,72(r1)   \n" // RG_ASMCALL, 16(RG_REAL_STACK)
01913 "    stw        r8,76(r1)   \n" // RG_INSTRUCTIONS, 20(RG_REAL_STACK)
01914 "    stw        r9,80(r1)   \n" // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
01915 "    stw        r10,84(r1)  \n" // RG_VM, 28(RG_REAL_STACK)
01916 "    stw        r13,88(r1)  \n" // RG_SECOND, 32(RG_REAL_STACK) // link register
01917 
01918     // save the vm stack position to allow recursive VM entry
01919 "    addi   r13,r3,-4       \n" // RG_TOP, RG_STACK, -4
01920 "    stw        r13,0(r10)  \n" //RG_TOP, VM_OFFSET_PROGRAM_STACK(RG_VM)
01921 
01922     // save the system call number as the 0th parameter
01923 "    add        r3,r3,r5    \n" // r3,  RG_STACK, RG_MEMBASE        // r3 is the first parameter to vm->systemCalls
01924 "    stwu   r12,4(r3)       \n" // RG_TOP, 4(r3)
01925 
01926     // make the system call with the address of all the VM parms as a parameter
01927     // vm->systemCalls( &parms )
01928 "    lwz        r12,4(r10)  \n" // RG_TOP, VM_OFFSET_SYSTEM_CALL(RG_VM)
01929 "    mtctr  r12         \n" // RG_TOP
01930 "    bcctrl 20,0            \n"
01931 "    mr     r12,r3          \n" // RG_TOP, r3
01932 
01933     // pop our saved registers
01934 "       lwz     r3,56(r1)   \n" // RG_STACK, 0(RG_REAL_STACK)
01935 "       lwz     r4,60(r1)   \n" // RG_OPSTACK, 4(RG_REAL_STACK)
01936 "       lwz     r5,64(r1)   \n" // RG_MEMBASE, 8(RG_REAL_STACK)
01937 "       lwz     r6,68(r1)   \n" // RG_MEMMASK, 12(RG_REAL_STACK)
01938 "       lwz     r7,72(r1)   \n" // RG_ASMCALL, 16(RG_REAL_STACK)
01939 "       lwz     r8,76(r1)   \n" // RG_INSTRUCTIONS, 20(RG_REAL_STACK)
01940 "       lwz     r9,80(r1)   \n" // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
01941 "       lwz     r10,84(r1)  \n" // RG_VM, 28(RG_REAL_STACK)
01942 "       lwz     r13,88(r1)  \n" // RG_SECOND, 32(RG_REAL_STACK)
01943 "    addi   r1,r1,92        \n" // RG_REAL_STACK, RG_REAL_STACK, 36
01944 
01945     // restore the old link register
01946 "    mtlr   r13         \n" // RG_SECOND
01947 
01948     // save off the return value
01949 "    stwu   r12,4(r4)       \n" // RG_TOP, 0(RG_OPSTACK)
01950 
01951     // GCC adds its own prolog / epliog code
01952  );
01953 }
01954 #else
01955 
01956 // codewarrior version
01957 
01958 void asm AsmCall( void ) {
01959 
01960     // pop off the destination instruction
01961 
01962     lwz     r12,0(r4)   // RG_TOP, 0(RG_OPSTACK)
01963 
01964     addi    r4,r4,-4    // RG_OPSTACK, RG_OPSTACK, -4
01965 
01966 
01967 
01968     // see if it is a system trap
01969 
01970     cmpwi   r12,0       // RG_TOP, 0
01971 
01972     bc      12,0, systemTrap
01973 
01974 
01975 
01976     // calling another VM function, so lookup in instructionPointers
01977 
01978     slwi    r12,r12,2       // RG_TOP,RG_TOP,2
01979 
01980                         // FIXME: range check
01981 
01982     lwzx    r12, r8, r12    // RG_TOP, RG_INSTRUCTIONS(RG_TOP)  
01983 
01984     mtctr   r12         // RG_TOP
01985 
01986 
01987 
01988     bcctr   20,0        // when it hits a leave, it will branch to the current link register
01989 
01990 
01991 
01992     // calling a system trap
01993 
01994 systemTrap:
01995 
01996     // convert to positive system call number
01997 
01998     subfic  r12,r12,-1
01999 
02000 
02001 
02002     // save all our registers, including the current link register
02003 
02004     mflr    r13         // RG_SECOND        // copy off our link register
02005 
02006     addi    r1,r1,-92   // required 24 byets of linkage, 32 bytes of parameter, plus our saves
02007 
02008     stw     r3,56(r1)   // RG_STACK, -36(REAL_STACK)
02009 
02010     stw     r4,60(r1)   // RG_OPSTACK, 4(RG_REAL_STACK)
02011 
02012     stw     r5,64(r1)   // RG_MEMBASE, 8(RG_REAL_STACK)
02013 
02014     stw     r6,68(r1)   // RG_MEMMASK, 12(RG_REAL_STACK)
02015 
02016     stw     r7,72(r1)   // RG_ASMCALL, 16(RG_REAL_STACK)
02017 
02018     stw     r8,76(r1)   // RG_INSTRUCTIONS, 20(RG_REAL_STACK)
02019 
02020     stw     r9,80(r1)   // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
02021 
02022     stw     r10,84(r1)  // RG_VM, 28(RG_REAL_STACK)
02023 
02024     stw     r13,88(r1)  // RG_SECOND, 32(RG_REAL_STACK) // link register
02025 
02026 
02027 
02028     // save the vm stack position to allow recursive VM entry
02029 
02030     addi    r13,r3,-4   // RG_TOP, RG_STACK, -4
02031 
02032     stw     r13,0(r10)  //RG_TOP, VM_OFFSET_PROGRAM_STACK(RG_VM)
02033 
02034 
02035 
02036     // save the system call number as the 0th parameter
02037 
02038     add     r3,r3,r5    // r3,  RG_STACK, RG_MEMBASE        // r3 is the first parameter to vm->systemCalls
02039 
02040     stwu    r12,4(r3)   // RG_TOP, 4(r3)
02041 
02042 
02043 
02044     // make the system call with the address of all the VM parms as a parameter
02045 
02046     // vm->systemCalls( &parms )
02047 
02048     lwz     r12,4(r10)  // RG_TOP, VM_OFFSET_SYSTEM_CALL(RG_VM)
02049 
02050     
02051 
02052     // perform macos cross fragment fixup crap
02053 
02054     lwz     r9,0(r12)
02055 
02056     stw     r2,52(r1)   // save old TOC
02057 
02058     lwz     r2,4(r12)
02059 
02060         
02061 
02062     mtctr   r9          // RG_TOP
02063 
02064     bcctrl  20,0
02065 
02066     
02067 
02068     lwz     r2,52(r1)   // restore TOC
02069 
02070     
02071 
02072     mr      r12,r3      // RG_TOP, r3
02073 
02074 
02075 
02076     // pop our saved registers
02077 
02078     lwz     r3,56(r1)   // RG_STACK, 0(RG_REAL_STACK)
02079 
02080     lwz     r4,60(r1)   // RG_OPSTACK, 4(RG_REAL_STACK)
02081 
02082     lwz     r5,64(r1)   // RG_MEMBASE, 8(RG_REAL_STACK)
02083 
02084     lwz     r6,68(r1)   // RG_MEMMASK, 12(RG_REAL_STACK)
02085 
02086     lwz     r7,72(r1)   // RG_ASMCALL, 16(RG_REAL_STACK)
02087 
02088     lwz     r8,76(r1)   // RG_INSTRUCTIONS, 20(RG_REAL_STACK)
02089 
02090     lwz     r9,80(r1)   // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
02091 
02092     lwz     r10,84(r1)  // RG_VM, 28(RG_REAL_STACK)
02093 
02094     lwz     r13,88(r1)  // RG_SECOND, 32(RG_REAL_STACK)
02095 
02096     addi    r1,r1,92    // RG_REAL_STACK, RG_REAL_STACK, 36
02097 
02098 
02099 
02100     // restore the old link register
02101 
02102     mtlr    r13         // RG_SECOND
02103 
02104 
02105 
02106     // save off the return value
02107 
02108     stwu    r12,4(r4)   // RG_TOP, 0(RG_OPSTACK)
02109 
02110 
02111 
02112     blr
02113 
02114 }
02115 
02116 
02117 
02118 
02119 #endif

Generated on Thu Aug 25 12:37:49 2005 for Quake III Arena by  doxygen 1.3.9.1