Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

vm_ppc.c (48567B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 // vm_ppc.c
     23 // ppc dynamic compiler
     24 
     25 #include "vm_local.h"
     26 
     27 #pragma opt_pointer_analysis off
     28 
     29 
     30 typedef enum {
     31     R_REAL_STACK = 1,
     32 	// registers 3-11 are the parameter passing registers
     33 	
     34 	// state
     35 	R_STACK = 3,			// local
     36 	R_OPSTACK,				// global
     37 
     38 	// constants	
     39 	R_MEMBASE,			// global
     40 	R_MEMMASK,
     41 	R_ASMCALL,			// global
     42     R_INSTRUCTIONS,		// global
     43     R_NUM_INSTRUCTIONS,	// global
     44     R_CVM,				// currentVM
     45     
     46 	// temps
     47 	R_TOP = 11,
     48 	R_SECOND = 12,
     49 	R_EA = 2				// effective address calculation
     50 	 
     51 } regNums_t;
     52 
     53 #define	RG_REAL_STACK		r1
     54 #define	RG_STACK			r3
     55 #define	RG_OPSTACK			r4
     56 #define	RG_MEMBASE			r5
     57 #define	RG_MEMMASK			r6
     58 #define	RG_ASMCALL			r7
     59 #define	RG_INSTRUCTIONS		r8
     60 #define	RG_NUM_INSTRUCTIONS	r9
     61 #define	RG_CVM				r10
     62 #define	RG_TOP				r12
     63 #define	RG_SECOND			r13
     64 #define	RG_EA 				r14
     65 
     66 // this doesn't have the low order bits set for instructions i'm not using...
     67 typedef enum {
     68 	PPC_TDI		= 0x08000000,
     69 	PPC_TWI		= 0x0c000000,
     70 	PPC_MULLI	= 0x1c000000,
     71 	PPC_SUBFIC	= 0x20000000,
     72 	PPC_CMPI	= 0x28000000,
     73 	PPC_CMPLI	= 0x2c000000,
     74 	PPC_ADDIC	= 0x30000000,
     75 	PPC_ADDIC_	= 0x34000000,
     76 	PPC_ADDI	= 0x38000000,
     77 	PPC_ADDIS	= 0x3c000000,
     78 	PPC_BC		= 0x40000000,
     79 	PPC_SC		= 0x44000000,
     80 	PPC_B		= 0x48000000,
     81 
     82 	PPC_MCRF	= 0x4c000000,
     83 	PPC_BCLR	= 0x4c000020,
     84 	PPC_RFID	= 0x4c000000,
     85 	PPC_CRNOR	= 0x4c000000,
     86 	PPC_RFI		= 0x4c000000,
     87 	PPC_CRANDC	= 0x4c000000,
     88 	PPC_ISYNC	= 0x4c000000,
     89 	PPC_CRXOR	= 0x4c000000,
     90 	PPC_CRNAND	= 0x4c000000,
     91 	PPC_CREQV	= 0x4c000000,
     92 	PPC_CRORC	= 0x4c000000,
     93 	PPC_CROR	= 0x4c000000,
     94 //------------
     95 	PPC_BCCTR	= 0x4c000420,
     96 	PPC_RLWIMI	= 0x50000000,
     97 	PPC_RLWINM	= 0x54000000,
     98 	PPC_RLWNM	= 0x5c000000,
     99 	PPC_ORI		= 0x60000000,
    100 	PPC_ORIS	= 0x64000000,
    101 	PPC_XORI	= 0x68000000,
    102 	PPC_XORIS	= 0x6c000000,
    103 	PPC_ANDI_	= 0x70000000,
    104 	PPC_ANDIS_	= 0x74000000,
    105 	PPC_RLDICL	= 0x78000000,
    106 	PPC_RLDICR	= 0x78000000,
    107 	PPC_RLDIC	= 0x78000000,
    108 	PPC_RLDIMI	= 0x78000000,
    109 	PPC_RLDCL	= 0x78000000,
    110 	PPC_RLDCR	= 0x78000000,
    111 	PPC_CMP		= 0x7c000000,
    112 	PPC_TW		= 0x7c000000,
    113 	PPC_SUBFC	= 0x7c000010,
    114 	PPC_MULHDU	= 0x7c000000,
    115 	PPC_ADDC	= 0x7c000014,
    116 	PPC_MULHWU	= 0x7c000000,
    117 	PPC_MFCR	= 0x7c000000,
    118 	PPC_LWAR	= 0x7c000000,
    119 	PPC_LDX		= 0x7c000000,
    120 	PPC_LWZX	= 0x7c00002e,
    121 	PPC_SLW		= 0x7c000030,
    122 	PPC_CNTLZW	= 0x7c000000,
    123 	PPC_SLD		= 0x7c000000,
    124 	PPC_AND		= 0x7c000038,
    125 	PPC_CMPL	= 0x7c000040,
    126 	PPC_SUBF	= 0x7c000050,
    127 	PPC_LDUX	= 0x7c000000,
    128 //------------
    129 	PPC_DCBST	= 0x7c000000,
    130 	PPC_LWZUX	= 0x7c00006c,
    131 	PPC_CNTLZD	= 0x7c000000,
    132 	PPC_ANDC	= 0x7c000000,
    133 	PPC_TD		= 0x7c000000,
    134 	PPC_MULHD	= 0x7c000000,
    135 	PPC_MULHW	= 0x7c000000,
    136 	PPC_MTSRD	= 0x7c000000,
    137 	PPC_MFMSR	= 0x7c000000,
    138 	PPC_LDARX	= 0x7c000000,
    139 	PPC_DCBF	= 0x7c000000,
    140 	PPC_LBZX	= 0x7c0000ae,
    141 	PPC_NEG		= 0x7c000000,
    142 	PPC_MTSRDIN	= 0x7c000000,
    143 	PPC_LBZUX	= 0x7c000000,
    144 	PPC_NOR		= 0x7c0000f8,
    145 	PPC_SUBFE	= 0x7c000000,
    146 	PPC_ADDE	= 0x7c000000,
    147 	PPC_MTCRF	= 0x7c000000,
    148 	PPC_MTMSR	= 0x7c000000,
    149 	PPC_STDX	= 0x7c000000,
    150 	PPC_STWCX_	= 0x7c000000,
    151 	PPC_STWX	= 0x7c00012e,
    152 	PPC_MTMSRD	= 0x7c000000,
    153 	PPC_STDUX	= 0x7c000000,
    154 	PPC_STWUX	= 0x7c00016e,
    155 	PPC_SUBFZE	= 0x7c000000,
    156 	PPC_ADDZE	= 0x7c000000,
    157 	PPC_MTSR	= 0x7c000000,
    158 	PPC_STDCX_	= 0x7c000000,
    159 	PPC_STBX	= 0x7c0001ae,
    160 	PPC_SUBFME	= 0x7c000000,
    161 	PPC_MULLD	= 0x7c000000,
    162 //------------
    163 	PPC_ADDME	= 0x7c000000,
    164 	PPC_MULLW	= 0x7c0001d6,
    165 	PPC_MTSRIN	= 0x7c000000,
    166 	PPC_DCBTST	= 0x7c000000,
    167 	PPC_STBUX	= 0x7c000000,
    168 	PPC_ADD		= 0x7c000214,
    169 	PPC_DCBT	= 0x7c000000,
    170 	PPC_LHZX	= 0x7c00022e,
    171 	PPC_EQV		= 0x7c000000,
    172 	PPC_TLBIE	= 0x7c000000,
    173 	PPC_ECIWX	= 0x7c000000,
    174 	PPC_LHZUX	= 0x7c000000,
    175 	PPC_XOR		= 0x7c000278,
    176 	PPC_MFSPR	= 0x7c0002a6,
    177 	PPC_LWAX	= 0x7c000000,
    178 	PPC_LHAX	= 0x7c000000,
    179 	PPC_TLBIA	= 0x7c000000,
    180 	PPC_MFTB	= 0x7c000000,
    181 	PPC_LWAUX	= 0x7c000000,
    182 	PPC_LHAUX	= 0x7c000000,
    183 	PPC_STHX	= 0x7c00032e,
    184 	PPC_ORC		= 0x7c000338,
    185 	PPC_SRADI	= 0x7c000000,
    186 	PPC_SLBIE	= 0x7c000000,
    187 	PPC_ECOWX	= 0x7c000000,
    188 	PPC_STHUX	= 0x7c000000,
    189 	PPC_OR		= 0x7c000378,
    190 	PPC_DIVDU	= 0x7c000000,
    191 	PPC_DIVWU	= 0x7c000396,
    192 	PPC_MTSPR	= 0x7c0003a6,
    193 	PPC_DCBI	= 0x7c000000,
    194 	PPC_NAND	= 0x7c000000,
    195 	PPC_DIVD	= 0x7c000000,
    196 //------------
    197 	PPC_DIVW	= 0x7c0003d6,
    198 	PPC_SLBIA	= 0x7c000000,
    199 	PPC_MCRXR	= 0x7c000000,
    200 	PPC_LSWX	= 0x7c000000,
    201 	PPC_LWBRX	= 0x7c000000,
    202 	PPC_LFSX	= 0x7c000000,
    203 	PPC_SRW		= 0x7c000430,
    204 	PPC_SRD		= 0x7c000000,
    205 	PPC_TLBSYNC	= 0x7c000000,
    206 	PPC_LFSUX	= 0x7c000000,
    207 	PPC_MFSR	= 0x7c000000,
    208 	PPC_LSWI	= 0x7c000000,
    209 	PPC_SYNC	= 0x7c000000,
    210 	PPC_LFDX	= 0x7c000000,
    211 	PPC_LFDUX	= 0x7c000000,
    212 	PPC_MFSRIN	= 0x7c000000,
    213 	PPC_STSWX	= 0x7c000000,
    214 	PPC_STWBRX	= 0x7c000000,
    215 	PPC_STFSX	= 0x7c000000,
    216 	PPC_STFSUX	= 0x7c000000,
    217 	PPC_STSWI	= 0x7c000000,
    218 	PPC_STFDX	= 0x7c000000,
    219 	PPC_DCBA	= 0x7c000000,
    220 	PPC_STFDUX	= 0x7c000000,
    221 	PPC_LHBRX	= 0x7c000000,
    222 	PPC_SRAW	= 0x7c000630,
    223 	PPC_SRAD	= 0x7c000000,
    224 	PPC_SRAWI	= 0x7c000000,
    225 	PPC_EIEIO	= 0x7c000000,
    226 	PPC_STHBRX	= 0x7c000000,
    227 	PPC_EXTSH	= 0x7c000734,
    228 	PPC_EXTSB	= 0x7c000774,
    229 	PPC_ICBI	= 0x7c000000,
    230 //------------
    231 	PPC_STFIWX	= 0x7c0007ae,
    232 	PPC_EXTSW	= 0x7c000000,
    233 	PPC_DCBZ	= 0x7c000000,
    234 	PPC_LWZ		= 0x80000000,
    235 	PPC_LWZU	= 0x84000000,
    236 	PPC_LBZ		= 0x88000000,
    237 	PPC_LBZU	= 0x8c000000,
    238 	PPC_STW		= 0x90000000,
    239 	PPC_STWU	= 0x94000000,
    240 	PPC_STB		= 0x98000000,
    241 	PPC_STBU	= 0x9c000000,
    242 	PPC_LHZ		= 0xa0000000,
    243 	PPC_LHZU	= 0xa4000000,
    244 	PPC_LHA		= 0xa8000000,
    245 	PPC_LHAU	= 0xac000000,
    246 	PPC_STH		= 0xb0000000,
    247 	PPC_STHU	= 0xb4000000,
    248 	PPC_LMW		= 0xb8000000,
    249 	PPC_STMW	= 0xbc000000,
    250 	PPC_LFS		= 0xc0000000,
    251 	PPC_LFSU	= 0xc4000000,
    252 	PPC_LFD		= 0xc8000000,
    253 	PPC_LFDU	= 0xcc000000,
    254 	PPC_STFS	= 0xd0000000,
    255 	PPC_STFSU	= 0xd4000000,
    256 	PPC_STFD	= 0xd8000000,
    257 	PPC_STFDU	= 0xdc000000,
    258 	PPC_LD		= 0xe8000000,
    259 	PPC_LDU		= 0xe8000001,
    260 	PPC_LWA		= 0xe8000002,
    261 	PPC_FDIVS	= 0xec000024,
    262 	PPC_FSUBS	= 0xec000028,
    263 	PPC_FADDS	= 0xec00002a,
    264 //------------
    265 	PPC_FSQRTS	= 0xec000000,
    266 	PPC_FRES	= 0xec000000,
    267 	PPC_FMULS	= 0xec000032,
    268 	PPC_FMSUBS	= 0xec000000,
    269 	PPC_FMADDS	= 0xec000000,
    270 	PPC_FNMSUBS	= 0xec000000,
    271 	PPC_FNMADDS	= 0xec000000,
    272 	PPC_STD		= 0xf8000000,
    273 	PPC_STDU	= 0xf8000001,
    274 	PPC_FCMPU	= 0xfc000000,
    275 	PPC_FRSP	= 0xfc000018,
    276 	PPC_FCTIW	= 0xfc000000,
    277 	PPC_FCTIWZ	= 0xfc00001e,
    278 	PPC_FDIV	= 0xfc000000,
    279 	PPC_FSUB	= 0xfc000028,
    280 	PPC_FADD	= 0xfc000000,
    281 	PPC_FSQRT	= 0xfc000000,
    282 	PPC_FSEL	= 0xfc000000,
    283 	PPC_FMUL	= 0xfc000000,
    284 	PPC_FRSQRTE	= 0xfc000000,
    285 	PPC_FMSUB	= 0xfc000000,
    286 	PPC_FMADD	= 0xfc000000,
    287 	PPC_FNMSUB	= 0xfc000000,
    288 	PPC_FNMADD	= 0xfc000000,
    289 	PPC_FCMPO	= 0xfc000000,
    290 	PPC_MTFSB1	= 0xfc000000,
    291 	PPC_FNEG	= 0xfc000050,
    292 	PPC_MCRFS	= 0xfc000000,
    293 	PPC_MTFSB0	= 0xfc000000,
    294 	PPC_FMR		= 0xfc000000,
    295 	PPC_MTFSFI	= 0xfc000000,
    296 	PPC_FNABS	= 0xfc000000,
    297 	PPC_FABS	= 0xfc000000,
    298 //------------
    299 	PPC_MFFS	= 0xfc000000,
    300 	PPC_MTFSF	= 0xfc000000,
    301 	PPC_FCTID	= 0xfc000000,
    302 	PPC_FCTIDZ	= 0xfc000000,
    303 	PPC_FCFID	= 0xfc000000
    304 	
    305 } ppcOpcodes_t;
    306 
    307 
    308 // the newly generated code
    309 static	unsigned	*buf;
    310 static	int		compiledOfs;	// in dwords
    311 
    312 // fromt the original bytecode
    313 static	byte	*code;
    314 static	int		pc;
    315 
    316 void AsmCall( void );
    317 
    318 double	itofConvert[2];
    319 
    320 static int	Constant4( void ) {
    321 	int		v;
    322 
    323 	v = code[pc] | (code[pc+1]<<8) | (code[pc+2]<<16) | (code[pc+3]<<24);
    324 	pc += 4;
    325 	return v;
    326 }
    327 
    328 static int	Constant1( void ) {
    329 	int		v;
    330 
    331 	v = code[pc];
    332 	pc += 1;
    333 	return v;
    334 }
    335 
    336 static void Emit4( int i ) {
    337 	buf[ compiledOfs ] = i;
    338 	compiledOfs++;
    339 }
    340 
    341 static void Inst( int opcode, int destReg, int aReg, int bReg ) {
    342     unsigned		r;
    343 
    344     r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) ;
    345     buf[ compiledOfs ] = r;
    346     compiledOfs++;
    347 }
    348 
    349 static void Inst4( int opcode, int destReg, int aReg, int bReg, int cReg ) {
    350     unsigned		r;
    351 
    352     r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) | ( cReg << 6 );
    353     buf[ compiledOfs ] = r;
    354     compiledOfs++;
    355 }
    356 
    357 static void InstImm( int opcode, int destReg, int aReg, int immediate ) {
    358 	unsigned		r;
    359 	
    360 	if ( immediate > 32767 || immediate < -32768 ) {
    361 	    Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range, opcode %x,%d,%d", immediate, opcode, destReg, aReg );
    362 	}
    363 	r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff );
    364 	buf[ compiledOfs ] = r;
    365 	compiledOfs++;
    366 }
    367 
    368 static void InstImmU( int opcode, int destReg, int aReg, int immediate ) {
    369 	unsigned		r;
    370 	
    371 	if ( immediate > 0xffff || immediate < 0 ) {
    372 		Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range", immediate );
    373 	}
    374     r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff );
    375 	buf[ compiledOfs ] = r;
    376 	compiledOfs++;
    377 }
    378 
    379 static qboolean	rtopped;
    380 static int pop0, pop1, oc0, oc1;
    381 static vm_t *tvm;
    382 static int instruction;
    383 static byte *jused;
    384 static int pass;
    385 
    386 static void ltop() {
    387     if (rtopped == qfalse) {
    388 	InstImm( PPC_LWZ, R_TOP, R_OPSTACK, 0 );		// get value from opstack
    389     }
    390 }
    391 
    392 static void ltopandsecond() {
    393     if (pass>=0 && buf[compiledOfs-1] == (PPC_STWU |  R_TOP<<21 | R_OPSTACK<<16 | 4 ) && jused[instruction]==0 ) {
    394 	compiledOfs--;
    395 	if (!pass) {
    396 	    tvm->instructionPointers[instruction] = compiledOfs * 4;
    397 	}
    398 	InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 );	// get value from opstack
    399 	InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
    400     } else if (pass>=0 && buf[compiledOfs-1] == (PPC_STW |  R_TOP<<21 | R_OPSTACK<<16 | 0 )  && jused[instruction]==0 ) {
    401 	compiledOfs--;
    402 	if (!pass) {
    403 	    tvm->instructionPointers[instruction] = compiledOfs * 4;
    404 	}
    405 	InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, -4 );	// get value from opstack
    406 	InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 );
    407     } else {
    408 	ltop();		// get value from opstack
    409 	InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, -4 );	// get value from opstack
    410 	InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 );
    411     }
    412     rtopped = qfalse;
    413 }
    414 
    415 // TJW: Unused
    416 #if 0
    417 static void fltop() {
    418     if (rtopped == qfalse) {
    419 	InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 );		// get value from opstack
    420     }
    421 }
    422 #endif
    423 
    424 static void fltopandsecond() {
    425 	InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 );		// get value from opstack
    426 	InstImm( PPC_LFS, R_SECOND, R_OPSTACK, -4 );	// get value from opstack
    427 	InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 );
    428     rtopped = qfalse;
    429 	return;
    430 }
    431 
    432 /*
    433 =================
    434 VM_Compile
    435 =================
    436 */
    437 void VM_Compile( vm_t *vm, vmHeader_t *header ) {
    438 	int		op;
    439 	int		maxLength;
    440 	int		v;
    441 	int		i;
    442         
    443 	// set up the into-to-float variables
    444    	((int *)itofConvert)[0] = 0x43300000;
    445    	((int *)itofConvert)[1] = 0x80000000;
    446    	((int *)itofConvert)[2] = 0x43300000;
    447 
    448 	// allocate a very large temp buffer, we will shrink it later
    449 	maxLength = header->codeLength * 8;
    450 	buf = Z_Malloc( maxLength );
    451 	jused = Z_Malloc(header->instructionCount + 2);
    452 	Com_Memset(jused, 0, header->instructionCount+2);
    453 	
    454     // compile everything twice, so the second pass will have valid instruction
    455     // pointers for branches
    456     for ( pass = -1 ; pass < 2 ; pass++ ) {
    457 
    458 	rtopped = qfalse;
    459         // translate all instructions
    460         pc = 0;
    461 	
    462 	pop0 = 343545;
    463 	pop1 = 2443545;
    464 	oc0 = -2343535;
    465 	oc1 = 24353454;
    466 	tvm = vm;
    467         code = (byte *)header + header->codeOffset;
    468         compiledOfs = 0;
    469 #ifndef __GNUC__
    470 		// metrowerks seems to require this header in front of functions
    471 		Emit4( (int)(buf+2) );
    472 		Emit4( 0 );
    473 #endif
    474 
    475 		for ( instruction = 0 ; instruction < header->instructionCount ; instruction++ ) {
    476             if ( compiledOfs*4 > maxLength - 16 ) {
    477                 Com_Error( ERR_DROP, "VM_Compile: maxLength exceeded" );
    478             }
    479 
    480             op = code[ pc ];
    481             if ( !pass ) {
    482                 vm->instructionPointers[ instruction ] = compiledOfs * 4;
    483             }
    484             pc++;
    485             switch ( op ) {
    486             case 0:
    487                 break;
    488             case OP_BREAK:
    489                 InstImmU( PPC_ADDI, R_TOP, 0, 0 );
    490                 InstImm( PPC_LWZ, R_TOP, R_TOP, 0 );			// *(int *)0 to crash to debugger
    491 		rtopped = qfalse;
    492                 break;
    493             case OP_ENTER:
    494                 InstImm( PPC_ADDI, R_STACK, R_STACK, -Constant4() );	// sub R_STACK, R_STACK, imm
    495 		rtopped = qfalse;
    496                 break;
    497             case OP_CONST:
    498                 v = Constant4();
    499 		if (code[pc] == OP_LOAD4 || code[pc] == OP_LOAD2 || code[pc] == OP_LOAD1) {
    500 		    v &= vm->dataMask;
    501 		}
    502                 if ( v < 32768 && v >= -32768 ) {
    503                     InstImmU( PPC_ADDI, R_TOP, 0, v & 0xffff );
    504                 } else {
    505                     InstImmU( PPC_ADDIS, R_TOP, 0, (v >> 16)&0xffff );
    506                     if ( v & 0xffff ) {
    507                         InstImmU( PPC_ORI, R_TOP, R_TOP, v & 0xffff );
    508                     }
    509                 }
    510 		if (code[pc] == OP_LOAD4) {
    511 		    Inst( PPC_LWZX, R_TOP, R_TOP, R_MEMBASE );		// load from memory base
    512 		    pc++;
    513 		    instruction++;
    514 		} else if (code[pc] == OP_LOAD2) {
    515 		    Inst( PPC_LHZX, R_TOP, R_TOP, R_MEMBASE );		// load from memory base
    516 		    pc++;
    517 		    instruction++;
    518 		} else if (code[pc] == OP_LOAD1) {
    519 		    Inst( PPC_LBZX, R_TOP, R_TOP, R_MEMBASE );		// load from memory base
    520 		    pc++;
    521 		    instruction++;
    522 		}
    523 		if (code[pc] == OP_STORE4) {
    524 		    InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 );	// get value from opstack
    525 		    InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
    526 		    //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND );	// mask it
    527 		    Inst( PPC_STWX, R_TOP, R_SECOND, R_MEMBASE );	// store from memory base
    528 		    pc++;
    529 		    instruction++;
    530 		    rtopped = qfalse;
    531 		    break;
    532 		} else if (code[pc] == OP_STORE2) {
    533 		    InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 );	// get value from opstack
    534 		    InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
    535 		    //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND );	// mask it
    536 		    Inst( PPC_STHX, R_TOP, R_SECOND, R_MEMBASE );	// store from memory base
    537 		    pc++;
    538 		    instruction++;
    539 		    rtopped = qfalse;
    540 		    break;
    541 		} else if (code[pc] == OP_STORE1) {
    542 		    InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 );	// get value from opstack
    543 		    InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
    544 		    //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND );	// mask it
    545 		    Inst( PPC_STBX, R_TOP, R_SECOND, R_MEMBASE );	// store from memory base
    546 		    pc++;
    547 		    instruction++;
    548 		    rtopped = qfalse;
    549 		    break;
    550 		}
    551 		if (code[pc] == OP_JUMP) {
    552 		    jused[v] = 1;
    553 		}
    554 		InstImm( PPC_STWU, R_TOP, R_OPSTACK, 4 );
    555 		rtopped = qtrue;
    556 		break;
    557             case OP_LOCAL:
    558 		oc0 = oc1;
    559 		oc1 = Constant4();
    560 		if (code[pc] == OP_LOAD4 || code[pc] == OP_LOAD2 || code[pc] == OP_LOAD1) {
    561 		    oc1 &= vm->dataMask;
    562 		}
    563                 InstImm( PPC_ADDI, R_TOP, R_STACK, oc1 );
    564 		if (code[pc] == OP_LOAD4) {
    565 		    Inst( PPC_LWZX, R_TOP, R_TOP, R_MEMBASE );		// load from memory base
    566 		    pc++;
    567 		    instruction++;
    568 		} else if (code[pc] == OP_LOAD2) {
    569 		    Inst( PPC_LHZX, R_TOP, R_TOP, R_MEMBASE );		// load from memory base
    570 		    pc++;
    571 		    instruction++;
    572 		} else if (code[pc] == OP_LOAD1) {
    573 		    Inst( PPC_LBZX, R_TOP, R_TOP, R_MEMBASE );		// load from memory base
    574 		    pc++;
    575 		    instruction++;
    576 		}
    577 		if (code[pc] == OP_STORE4) {
    578 		    InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 );		// get value from opstack
    579 		    InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
    580 		    //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND );	// mask it
    581 		    Inst( PPC_STWX, R_TOP, R_SECOND, R_MEMBASE );	// store from memory base
    582 		    pc++;
    583 		    instruction++;
    584 		    rtopped = qfalse;
    585 		    break;
    586 		} else if (code[pc] == OP_STORE2) {
    587 		    InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 );		// get value from opstack
    588 		    InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
    589 		    //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND );	// mask it
    590 		    Inst( PPC_STHX, R_TOP, R_SECOND, R_MEMBASE );	// store from memory base
    591 		    pc++;
    592 		    instruction++;
    593 		    rtopped = qfalse;
    594 		    break;
    595 		} else if (code[pc] == OP_STORE1) {
    596 		    InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 );		// get value from opstack
    597 		    InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
    598 		    //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND );	// mask it
    599 		    Inst( PPC_STBX, R_TOP, R_SECOND, R_MEMBASE );	// store from memory base
    600 		    pc++;
    601 		    instruction++;
    602 		    rtopped = qfalse;
    603 		    break;
    604 		}
    605                 InstImm( PPC_STWU, R_TOP, R_OPSTACK, 4 );
    606 		rtopped = qtrue;
    607                 break;
    608             case OP_ARG:
    609                 ltop();							// get value from opstack
    610                 InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
    611                 InstImm( PPC_ADDI, R_EA, R_STACK, Constant1() );	// location to put it
    612                 Inst( PPC_STWX, R_TOP, R_EA, R_MEMBASE );
    613 		rtopped = qfalse;
    614                 break;
    615             case OP_CALL:
    616                 Inst( PPC_MFSPR, R_SECOND, 8, 0 );			// move from link register
    617                 InstImm( PPC_STWU, R_SECOND, R_REAL_STACK, -16 );	// save off the old return address
    618 
    619                 Inst( PPC_MTSPR, R_ASMCALL, 9, 0 );			// move to count register
    620                 Inst( PPC_BCCTR | 1, 20, 0, 0 );			// jump and link to the count register
    621 
    622                 InstImm( PPC_LWZ, R_SECOND, R_REAL_STACK, 0 );		// fetch the old return address
    623                 InstImm( PPC_ADDI, R_REAL_STACK, R_REAL_STACK, 16 );
    624                 Inst( PPC_MTSPR, R_SECOND, 8, 0 );			// move to link register
    625 		rtopped = qfalse;
    626                 break;
    627             case OP_PUSH:
    628                 InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, 4 );
    629 		rtopped = qfalse;
    630                 break;
    631             case OP_POP:
    632                 InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
    633 		rtopped = qfalse;
    634                 break;
    635             case OP_LEAVE:
    636                 InstImm( PPC_ADDI, R_STACK, R_STACK, Constant4() );	// add R_STACK, R_STACK, imm
    637                 Inst( PPC_BCLR, 20, 0, 0 );							// branch unconditionally to link register
    638 		rtopped = qfalse;
    639                 break;
    640             case OP_LOAD4:
    641                 ltop();							// get value from opstack
    642 		//Inst( PPC_AND, R_MEMMASK, R_TOP, R_TOP );		// mask it
    643                 Inst( PPC_LWZX, R_TOP, R_TOP, R_MEMBASE );		// load from memory base
    644                 InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );
    645 		rtopped = qtrue;
    646                 break;
    647             case OP_LOAD2:
    648                 ltop();							// get value from opstack
    649 		//Inst( PPC_AND, R_MEMMASK, R_TOP, R_TOP );		// mask it
    650                 Inst( PPC_LHZX, R_TOP, R_TOP, R_MEMBASE );		// load from memory base
    651                 InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );
    652 		rtopped = qtrue;
    653                 break;
    654             case OP_LOAD1:
    655                 ltop();							// get value from opstack
    656 		//Inst( PPC_AND, R_MEMMASK, R_TOP, R_TOP );		// mask it
    657                 Inst( PPC_LBZX, R_TOP, R_TOP, R_MEMBASE );		// load from memory base
    658                 InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );
    659 		rtopped = qtrue;
    660                 break;
    661             case OP_STORE4:
    662                 ltopandsecond();					// get value from opstack
    663 		//Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND );		// mask it
    664                 Inst( PPC_STWX, R_TOP, R_SECOND, R_MEMBASE );		// store from memory base
    665 		rtopped = qfalse;
    666                 break;
    667             case OP_STORE2:
    668                 ltopandsecond();					// get value from opstack
    669 		//Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND );		// mask it
    670                 Inst( PPC_STHX, R_TOP, R_SECOND, R_MEMBASE );		// store from memory base
    671 		rtopped = qfalse;
    672                 break;
    673             case OP_STORE1:
    674                 ltopandsecond();					// get value from opstack
    675 		//Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND );		// mask it
    676                 Inst( PPC_STBX, R_TOP, R_SECOND, R_MEMBASE );		// store from memory base
    677 		rtopped = qfalse;
    678                 break;
    679 
    680             case OP_EQ:
    681                 ltopandsecond();					// get value from opstack
    682                 Inst( PPC_CMP, 0, R_SECOND, R_TOP );
    683                 i = Constant4();
    684 				jused[i] = 1;
    685                 InstImm( PPC_BC, 4, 2, 8 );
    686                 if ( pass==1 ) {
    687                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];                    
    688                 } else {
    689                     v = 0;             
    690                 }
    691                 Emit4(PPC_B | (v&0x3ffffff) );
    692 				rtopped = qfalse;
    693                 break;
    694             case OP_NE:
    695                 ltopandsecond();					// get value from opstack
    696                 Inst( PPC_CMP, 0, R_SECOND, R_TOP );
    697                 i = Constant4();
    698 				jused[i] = 1;
    699                 InstImm( PPC_BC, 12, 2, 8 );
    700                 if ( pass==1 ) {
    701                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];                    
    702                 } else {
    703                     v = 0;
    704                 }
    705                 Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
    706 //                InstImm( PPC_BC, 4, 2, v );
    707 
    708 				rtopped = qfalse;
    709                 break;
    710             case OP_LTI:
    711                 ltopandsecond();					// get value from opstack
    712                 Inst( PPC_CMP, 0, R_SECOND, R_TOP );
    713                 i = Constant4();
    714 				jused[i] = 1;
    715                 InstImm( PPC_BC, 4, 0, 8 );
    716                 if ( pass==1 ) {
    717                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
    718                 } else {
    719                     v = 0;
    720                 }
    721                 Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
    722 //                InstImm( PPC_BC, 12, 0, v );
    723 				rtopped = qfalse;
    724                 break;
    725             case OP_LEI:
    726                 ltopandsecond();					// get value from opstack
    727                 Inst( PPC_CMP, 0, R_SECOND, R_TOP );
    728                 i = Constant4();
    729 				jused[i] = 1;
    730                 InstImm( PPC_BC, 12, 1, 8 );
    731                 if ( pass==1 ) {
    732                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
    733                 } else {
    734                     v = 0;
    735                 }
    736                 Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
    737 //                InstImm( PPC_BC, 4, 1, v );
    738 				rtopped = qfalse;
    739                 break;
    740             case OP_GTI:
    741                 ltopandsecond();		// get value from opstack
    742                 Inst( PPC_CMP, 0, R_SECOND, R_TOP );
    743                 i = Constant4();
    744 				jused[i] = 1;
    745                 InstImm( PPC_BC, 4, 1, 8 );
    746                 if ( pass==1 ) {
    747                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
    748                 } else {
    749                     v = 0;
    750                 }
    751                 Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
    752 //                InstImm( PPC_BC, 12, 1, v );
    753 				rtopped = qfalse;
    754                 break;
    755             case OP_GEI:
    756                 ltopandsecond();		// get value from opstack
    757                 Inst( PPC_CMP, 0, R_SECOND, R_TOP );
    758                 i = Constant4();
    759 				jused[i] = 1;
    760                 InstImm( PPC_BC, 12, 0, 8 );
    761                 if ( pass==1 ) {
    762                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
    763                 } else {
    764                     v = 0;
    765                 }
    766                 Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
    767 //                InstImm( PPC_BC, 4, 0, v );
    768 				rtopped = qfalse;
    769                 break;
    770             case OP_LTU:
    771                 ltopandsecond();		// get value from opstack
    772                 Inst( PPC_CMPL, 0, R_SECOND, R_TOP );
    773                 i = Constant4();
    774 		jused[i] = 1;
    775                 InstImm( PPC_BC, 4, 0, 8 );
    776                 if ( pass==1 ) {
    777                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
    778                 } else {
    779                     v = 0;
    780                 }
    781                 Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
    782 //                InstImm( PPC_BC, 12, 0, v );
    783 		rtopped = qfalse;
    784                 break;
    785             case OP_LEU:
    786                 ltopandsecond();		// get value from opstack
    787                 Inst( PPC_CMPL, 0, R_SECOND, R_TOP );
    788                 i = Constant4();
    789 		jused[i] = 1;
    790                 InstImm( PPC_BC, 12, 1, 8 );
    791                 if ( pass==1 ) {
    792                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
    793                 } else {
    794                     v = 0;
    795                 }
    796                 Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
    797 //                InstImm( PPC_BC, 4, 1, v );
    798 		rtopped = qfalse;
    799                 break;
    800             case OP_GTU:
    801                 ltopandsecond();		// get value from opstack
    802                 Inst( PPC_CMPL, 0, R_SECOND, R_TOP );
    803                 i = Constant4();
    804 		jused[i] = 1;
    805                 InstImm( PPC_BC, 4, 1, 8 );
    806                 if ( pass==1 ) {
    807                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
    808                 } else {
    809                     v = 0;
    810                 }
    811                 Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
    812 //                InstImm( PPC_BC, 12, 1, v );
    813 		rtopped = qfalse;
    814                 break;
    815             case OP_GEU:
    816                 ltopandsecond();		// get value from opstack
    817                 Inst( PPC_CMPL, 0, R_SECOND, R_TOP );
    818                 i = Constant4();
    819 		jused[i] = 1;
    820                 InstImm( PPC_BC, 12, 0, 8 );
    821                 if ( pass==1 ) {
    822                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
    823                 } else {
    824                     v = 0;
    825                 }
    826                 Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
    827 //                InstImm( PPC_BC, 4, 0, v );
    828 		rtopped = qfalse;
    829                 break;
    830                 
    831             case OP_EQF:
    832                 fltopandsecond();		// get value from opstack
    833                 Inst( PPC_FCMPU, 0, R_TOP, R_SECOND );
    834                 i = Constant4();
    835 		jused[i] = 1;
    836                 InstImm( PPC_BC, 4, 2, 8 );
    837                 if ( pass==1 ) {
    838                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
    839                 } else {
    840                     v = 0;
    841                 }
    842                 Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
    843 //                InstImm( PPC_BC, 12, 2, v );
    844 		rtopped = qfalse;
    845                 break;			
    846             case OP_NEF:
    847                 fltopandsecond();		// get value from opstack
    848                 Inst( PPC_FCMPU, 0, R_TOP, R_SECOND );
    849                 i = Constant4();
    850 		jused[i] = 1;
    851                 InstImm( PPC_BC, 12, 2, 8 );
    852                 if ( pass==1 ) {
    853                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
    854                 } else {
    855                     v = 0;
    856                 }
    857                 Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
    858 //                InstImm( PPC_BC, 4, 2, v );
    859 		rtopped = qfalse;
    860                 break;			
    861             case OP_LTF:
    862                 fltopandsecond();		// get value from opstack
    863                 Inst( PPC_FCMPU, 0, R_SECOND, R_TOP );
    864                 i = Constant4();
    865 		jused[i] = 1;
    866                 InstImm( PPC_BC, 4, 0, 8 );
    867                 if ( pass==1 ) {
    868                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
    869                 } else {
    870                     v = 0;
    871                 }
    872                 Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
    873 //                InstImm( PPC_BC, 12, 0, v );
    874 		rtopped = qfalse;
    875                 break;			
    876             case OP_LEF:
    877                 fltopandsecond();		// get value from opstack
    878                 Inst( PPC_FCMPU, 0, R_SECOND, R_TOP );
    879                 i = Constant4();
    880 		jused[i] = 1;
    881                 InstImm( PPC_BC, 12, 1, 8 );
    882                 if ( pass==1 ) {
    883                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
    884                 } else {
    885                     v = 0;
    886                 }
    887                 Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
    888 //                InstImm( PPC_BC, 4, 1, v );
    889 		rtopped = qfalse;
    890                 break;			
    891             case OP_GTF:
    892                 fltopandsecond();		// get value from opstack
    893                 Inst( PPC_FCMPU, 0, R_SECOND, R_TOP );
    894                 i = Constant4();
    895 		jused[i] = 1;
    896                 InstImm( PPC_BC, 4, 1, 8 );
    897                 if ( pass==1 ) {
    898                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
    899                 } else {
    900                     v = 0;
    901                 }
    902                 Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
    903 //                InstImm( PPC_BC, 12, 1, v );
    904 		rtopped = qfalse;
    905                 break;			
    906             case OP_GEF:
    907                 fltopandsecond();		// get value from opstack
    908                 Inst( PPC_FCMPU, 0, R_SECOND, R_TOP );
    909                 i = Constant4();
    910 		jused[i] = 1;
    911                 InstImm( PPC_BC, 12, 0, 8 );
    912                 if ( pass==1 ) {
    913                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
    914                 } else {
    915                     v = 0;
    916                 }
    917                 Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
    918 //                InstImm( PPC_BC, 4, 0, v );
    919 		rtopped = qfalse;
    920                 break;
    921 
    922             case OP_NEGI:
    923                 ltop();		// get value from opstack
    924                 InstImm( PPC_SUBFIC, R_TOP, R_TOP, 0 );
    925                 InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );		// save value to opstack
    926 		rtopped = qtrue;
    927                 break;
    928             case OP_ADD:
    929                 ltop();		// get value from opstack
    930                 InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 );		// get value from opstack
    931                 Inst( PPC_ADD, R_TOP, R_TOP, R_SECOND );
    932                 InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );		// save value to opstack
    933 		rtopped = qtrue;
    934                 break;
    935             case OP_SUB:
    936                 ltop();		// get value from opstack
    937                 InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 );		// get value from opstack
    938                 Inst( PPC_SUBF, R_TOP, R_TOP, R_SECOND );
    939                 InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );		// save value to opstack
    940 		rtopped = qtrue;
    941                 break;
    942             case OP_DIVI:
    943                 ltop();		// get value from opstack
    944                 InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 );		// get value from opstack
    945                 Inst( PPC_DIVW, R_TOP, R_SECOND, R_TOP );
    946                 InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );		// save value to opstack
    947 		rtopped = qtrue;
    948                 break;
    949             case OP_DIVU:
    950                 ltop();		// get value from opstack
    951                 InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 );		// get value from opstack
    952                 Inst( PPC_DIVWU, R_TOP, R_SECOND, R_TOP );
    953                 InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );		// save value to opstack
    954 		rtopped = qtrue;
    955                 break;
    956             case OP_MODI:
    957                 ltop();		// get value from opstack
    958                 InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 );		// get value from opstack
    959                 Inst( PPC_DIVW, R_EA, R_SECOND, R_TOP );
    960                 Inst( PPC_MULLW, R_EA, R_TOP, R_EA );
    961                 Inst( PPC_SUBF, R_TOP, R_EA, R_SECOND );
    962                 InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );		// save value to opstack
    963 		rtopped = qtrue;
    964                 break;
    965             case OP_MODU:
    966                 ltop();		// get value from opstack
    967                 InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 );		// get value from opstack
    968                 Inst( PPC_DIVWU, R_EA, R_SECOND, R_TOP );
    969                 Inst( PPC_MULLW, R_EA, R_TOP, R_EA );
    970                 Inst( PPC_SUBF, R_TOP, R_EA, R_SECOND );
    971                 InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );		// save value to opstack
    972 		rtopped = qtrue;
    973                 break;
    974             case OP_MULI:
    975             case OP_MULU:
    976                 ltop();		// get value from opstack
    977                 InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 );		// get value from opstack
    978                 Inst( PPC_MULLW, R_TOP, R_SECOND, R_TOP );
    979                 InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );		// save value to opstack
    980 		rtopped = qtrue;
    981                 break;
    982             case OP_BAND:
    983                 ltop();		// get value from opstack
    984                 InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 );		// get value from opstack
    985                 Inst( PPC_AND, R_SECOND, R_TOP, R_TOP );
    986                 InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );		// save value to opstack
    987 		rtopped = qtrue;
    988                 break;
    989             case OP_BOR:
    990                 ltop();		// get value from opstack
    991                 InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 );		// get value from opstack
    992                 Inst( PPC_OR, R_SECOND, R_TOP, R_TOP );
    993                 InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );		// save value to opstack
    994 		rtopped = qtrue;
    995                 break;
    996             case OP_BXOR:
    997                 ltop();		// get value from opstack
    998                 InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 );		// get value from opstack
    999                 Inst( PPC_XOR, R_SECOND, R_TOP, R_TOP );
   1000                 InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );		// save value to opstack
   1001 		rtopped = qtrue;
   1002                 break;
   1003             case OP_BCOM:
   1004                 ltop();		// get value from opstack
   1005                 Inst( PPC_NOR, R_TOP, R_TOP, R_TOP );
   1006                 InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );		// save value to opstack
   1007 		rtopped = qtrue;
   1008                 break;
   1009             case OP_LSH:
   1010                 ltop();		// get value from opstack
   1011                 InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 );		// get value from opstack
   1012                 Inst( PPC_SLW, R_SECOND, R_TOP, R_TOP );
   1013                 InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );		// save value to opstack
   1014 		rtopped = qtrue;
   1015                 break;
   1016             case OP_RSHI:
   1017                 ltop();		// get value from opstack
   1018                 InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 );		// get value from opstack
   1019                 Inst( PPC_SRAW, R_SECOND, R_TOP, R_TOP );
   1020                 InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );		// save value to opstack
   1021 		rtopped = qtrue;
   1022                 break;
   1023             case OP_RSHU:
   1024                 ltop();		// get value from opstack
   1025                 InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 );		// get value from opstack
   1026                 Inst( PPC_SRW, R_SECOND, R_TOP, R_TOP );
   1027                 InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );		// save value to opstack
   1028 		rtopped = qtrue;
   1029                 break;
   1030 
   1031             case OP_NEGF:
   1032                 InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 );		// get value from opstack
   1033                 Inst( PPC_FNEG, R_TOP, 0, R_TOP );
   1034                 InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 );		// save value to opstack
   1035 		rtopped = qfalse;
   1036                 break;
   1037             case OP_ADDF:
   1038                 InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 );		// get value from opstack
   1039                 InstImm( PPC_LFSU, R_SECOND, R_OPSTACK, -4 );		// get value from opstack
   1040                 Inst( PPC_FADDS, R_TOP, R_SECOND, R_TOP );
   1041                 InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 );		// save value to opstack
   1042 		rtopped = qfalse;
   1043                 break;
   1044             case OP_SUBF:
   1045                 InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 );		// get value from opstack
   1046                 InstImm( PPC_LFSU, R_SECOND, R_OPSTACK, -4 );		// get value from opstack
   1047                 Inst( PPC_FSUBS, R_TOP, R_SECOND, R_TOP );
   1048                 InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 );		// save value to opstack
   1049 		rtopped = qfalse;
   1050                 break;
   1051             case OP_DIVF:
   1052                 InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 );		// get value from opstack
   1053                 InstImm( PPC_LFSU, R_SECOND, R_OPSTACK, -4 );		// get value from opstack
   1054                 Inst( PPC_FDIVS, R_TOP, R_SECOND, R_TOP );
   1055                 InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 );		// save value to opstack
   1056 		rtopped = qfalse;
   1057                 break;
   1058             case OP_MULF:
   1059                 InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 );		// get value from opstack
   1060                 InstImm( PPC_LFSU, R_SECOND, R_OPSTACK, -4 );		// get value from opstack
   1061                 Inst4( PPC_FMULS, R_TOP, R_SECOND, 0, R_TOP );
   1062                 InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 );		// save value to opstack
   1063 		rtopped = qfalse;
   1064                 break;
   1065 
   1066             case OP_CVIF:
   1067                 v = (int)&itofConvert;
   1068                 InstImmU( PPC_ADDIS, R_EA, 0, (v >> 16)&0xffff );
   1069                 InstImmU( PPC_ORI, R_EA, R_EA, v & 0xffff );
   1070 		InstImm( PPC_LWZ, R_TOP, R_OPSTACK, 0 );		// get value from opstack
   1071                 InstImmU( PPC_XORIS, R_TOP, R_TOP, 0x8000 );
   1072                 InstImm( PPC_STW, R_TOP, R_EA, 12 );
   1073                 InstImm( PPC_LFD, R_TOP, R_EA, 0 );
   1074                 InstImm( PPC_LFD, R_SECOND, R_EA, 8 );
   1075                 Inst( PPC_FSUB, R_TOP, R_SECOND, R_TOP );
   1076     //            Inst( PPC_FRSP, R_TOP, 0, R_TOP );
   1077                 InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 );		// save value to opstack
   1078 		rtopped = qfalse;
   1079                 break;
   1080             case OP_CVFI:
   1081                 InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 );		// get value from opstack
   1082                 Inst( PPC_FCTIWZ, R_TOP, 0, R_TOP );
   1083                 Inst( PPC_STFIWX, R_TOP, 0, R_OPSTACK );		// save value to opstack
   1084 		rtopped = qfalse;
   1085                 break;
   1086             case OP_SEX8:
   1087                 ltop();	// get value from opstack
   1088                 Inst( PPC_EXTSB, R_TOP, R_TOP, 0 );
   1089                 InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );
   1090 		rtopped = qtrue;
   1091                 break;
   1092             case OP_SEX16:
   1093                 ltop();	// get value from opstack
   1094                 Inst( PPC_EXTSH, R_TOP, R_TOP, 0 );
   1095                 InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );
   1096 		rtopped = qtrue;
   1097                 break;
   1098 
   1099             case OP_BLOCK_COPY:
   1100                 v = Constant4() >> 2;
   1101                 ltop();		// source
   1102                 InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, -4 );	// dest
   1103                 InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 );
   1104                 InstImmU( PPC_ADDI, R_EA, 0, v );				// count
   1105 				// FIXME: range check
   1106               	Inst( PPC_MTSPR, R_EA, 9, 0 );					// move to count register
   1107 
   1108                 Inst( PPC_ADD, R_TOP, R_TOP, R_MEMBASE );
   1109                 InstImm( PPC_ADDI, R_TOP, R_TOP, -4 );
   1110                 Inst( PPC_ADD, R_SECOND, R_SECOND, R_MEMBASE );
   1111                 InstImm( PPC_ADDI, R_SECOND, R_SECOND, -4 );
   1112 
   1113                 InstImm( PPC_LWZU, R_EA, R_TOP, 4 );		// source
   1114                 InstImm( PPC_STWU, R_EA, R_SECOND, 4 );	// dest
   1115                 Inst( PPC_BC | 0xfff8 , 16, 0, 0 );					// loop
   1116 		rtopped = qfalse;
   1117                 break;
   1118 
   1119             case OP_JUMP:
   1120                 ltop();	// get value from opstack
   1121                 InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
   1122                 Inst( PPC_RLWINM | ( 29 << 1 ), R_TOP, R_TOP, 2 );
   1123 		// FIXME: range check
   1124 		Inst( PPC_LWZX, R_TOP, R_TOP, R_INSTRUCTIONS );
   1125                 Inst( PPC_MTSPR, R_TOP, 9, 0 );		// move to count register
   1126                 Inst( PPC_BCCTR, 20, 0, 0 );		// jump to the count register
   1127 		rtopped = qfalse;
   1128                 break;
   1129             default:
   1130                 Com_Error( ERR_DROP, "VM_CompilePPC: bad opcode %i at instruction %i, offset %i", op, instruction, pc );
   1131             }
   1132 	    pop0 = pop1;
   1133 	    pop1 = op;
   1134         }
   1135 
   1136 	Com_Printf( "VM file %s pass %d compiled to %i bytes of code\n", vm->name, (pass+1), compiledOfs*4 );
   1137 
   1138     	if ( pass == 0 ) {
   1139 	    // copy to an exact size buffer on the hunk
   1140 	    vm->codeLength = compiledOfs * 4;
   1141 	    vm->codeBase = Hunk_Alloc( vm->codeLength, h_low );
   1142 	    Com_Memcpy( vm->codeBase, buf, vm->codeLength );
   1143 	    Z_Free( buf );
   1144 	
   1145 	    // offset all the instruction pointers for the new location
   1146 	    for ( i = 0 ; i < header->instructionCount ; i++ ) {
   1147 		vm->instructionPointers[i] += (int)vm->codeBase;
   1148 	    }
   1149 
   1150 	    // go back over it in place now to fixup reletive jump targets
   1151 	    buf = (unsigned *)vm->codeBase;
   1152 	}
   1153     }
   1154     Z_Free( jused );
   1155 }
   1156 
   1157 /*
   1158 ==============
   1159 VM_CallCompiled
   1160 
   1161 This function is called directly by the generated code
   1162 ==============
   1163 */
   1164 int	VM_CallCompiled( vm_t *vm, int *args ) {
   1165 	int		stack[1024];
   1166 	int		programStack;
   1167 	int		stackOnEntry;
   1168 	byte	*image;
   1169 
   1170 	currentVM = vm;
   1171 
   1172 	// interpret the code
   1173 	vm->currentlyInterpreting = qtrue;
   1174 
   1175 	// we might be called recursively, so this might not be the very top
   1176 	programStack = vm->programStack;
   1177 	stackOnEntry = programStack;
   1178 	image = vm->dataBase;
   1179 	
   1180 	// set up the stack frame 
   1181 	programStack -= 48;
   1182 
   1183 	*(int *)&image[ programStack + 44] = args[9];
   1184 	*(int *)&image[ programStack + 40] = args[8];
   1185 	*(int *)&image[ programStack + 36] = args[7];
   1186 	*(int *)&image[ programStack + 32] = args[6];
   1187 	*(int *)&image[ programStack + 28] = args[5];
   1188 	*(int *)&image[ programStack + 24] = args[4];
   1189 	*(int *)&image[ programStack + 20] = args[3];
   1190 	*(int *)&image[ programStack + 16] = args[2];
   1191 	*(int *)&image[ programStack + 12] = args[1];
   1192 	*(int *)&image[ programStack + 8 ] = args[0];
   1193 	*(int *)&image[ programStack + 4 ] = 0;	// return stack
   1194 	*(int *)&image[ programStack ] = -1;	// will terminate the loop on return
   1195 
   1196 	// off we go into generated code...
   1197 	// the PPC calling standard says the parms will all go into R3 - R11, so 
   1198 	// no special asm code is needed here
   1199 #ifdef __GNUC__
   1200 	((void(*)(int, int, int, int, int, int, int, int))(vm->codeBase))( 
   1201 		programStack, (int)&stack, 
   1202 		(int)image, vm->dataMask, (int)&AsmCall, 
   1203 		(int)vm->instructionPointers, vm->instructionPointersLength,
   1204         (int)vm );
   1205 #else
   1206 	((void(*)(int, int, int, int, int, int, int, int))(vm->codeBase))( 
   1207 		programStack, (int)&stack, 
   1208 		(int)image, vm->dataMask, *(int *)&AsmCall /* skip function pointer header */, 
   1209 		(int)vm->instructionPointers, vm->instructionPointersLength,
   1210         (int)vm );
   1211 #endif
   1212 	vm->programStack = stackOnEntry;
   1213 
   1214     vm->currentlyInterpreting = qfalse;
   1215 
   1216 	return stack[1];
   1217 }
   1218 
   1219 
   1220 /*
   1221 ==================
   1222 AsmCall
   1223 
   1224 Put this at end of file because gcc messes up debug line numbers 
   1225 ==================
   1226 */
   1227 #ifdef __GNUC__
   1228 
   1229 void AsmCall( void ) {
   1230 asm (
   1231      // pop off the destination instruction
   1232 "    lwz		r12,0(r4)	\n"	// RG_TOP, 0(RG_OPSTACK)
   1233 "    addi	r4,r4,-4		\n"	// RG_OPSTACK, RG_OPSTACK, -4 \n"
   1234 
   1235     // see if it is a system trap
   1236 "    cmpwi	r12,0			\n"	// RG_TOP, 0 \n"
   1237 "    bc		12,0, systemTrap	\n"
   1238 
   1239     // calling another VM function, so lookup in instructionPointers
   1240 "    slwi	r12,r12,2		\n"	// RG_TOP,RG_TOP,2
   1241                         // FIXME: range check
   1242 "    lwzx	r12, r8, r12		\n"	// RG_TOP, RG_INSTRUCTIONS(RG_TOP)	
   1243 "    mtctr	r12			\n"	// RG_TOP
   1244 );
   1245 
   1246 #if defined(MACOS_X) && defined(__OPTIMIZE__)
   1247     // On Mac OS X, gcc doesn't push a frame when we are optimized, so trying to tear it down results in grave disorder.
   1248 #warning Mac OS X optimization on, not popping GCC AsmCall frame
   1249 #else
   1250     // Mac OS X Server and unoptimized compiles include a GCC AsmCall frame
   1251     asm (
   1252 "	lwz		r1,0(r1)	\n"	// pop off the GCC AsmCall frame
   1253 "	lmw		r30,-8(r1)	\n"
   1254 );
   1255 #endif
   1256 
   1257 asm (
   1258 "	    bcctr	20,0		\n" // when it hits a leave, it will branch to the current link register
   1259 
   1260     // calling a system trap
   1261 "systemTrap:				\n"
   1262 	// convert to positive system call number
   1263 "	subfic	r12,r12,-1		\n"
   1264 
   1265     // save all our registers, including the current link register
   1266 "    mflr	r13			\n"	// RG_SECOND		// copy off our link register
   1267 "	addi	r1,r1,-92		\n"	// required 24 byets of linkage, 32 bytes of parameter, plus our saves
   1268 "    stw		r3,56(r1)	\n"	// RG_STACK, -36(REAL_STACK)
   1269 "    stw		r4,60(r1)	\n"	// RG_OPSTACK, 4(RG_REAL_STACK)
   1270 "    stw		r5,64(r1)	\n"	// RG_MEMBASE, 8(RG_REAL_STACK)
   1271 "    stw		r6,68(r1)	\n"	// RG_MEMMASK, 12(RG_REAL_STACK)
   1272 "    stw		r7,72(r1)	\n"	// RG_ASMCALL, 16(RG_REAL_STACK)
   1273 "    stw		r8,76(r1)	\n"	// RG_INSTRUCTIONS, 20(RG_REAL_STACK)
   1274 "    stw		r9,80(r1)	\n"	// RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
   1275 "    stw		r10,84(r1)	\n"	// RG_VM, 28(RG_REAL_STACK)
   1276 "    stw		r13,88(r1)	\n"	// RG_SECOND, 32(RG_REAL_STACK)	// link register
   1277 
   1278     // save the vm stack position to allow recursive VM entry
   1279 "    addi	r13,r3,-4		\n"	// RG_TOP, RG_STACK, -4
   1280 "    stw		r13,0(r10)	\n"	//RG_TOP, VM_OFFSET_PROGRAM_STACK(RG_VM)
   1281 
   1282     // save the system call number as the 0th parameter
   1283 "    add		r3,r3,r5	\n"	// r3,  RG_STACK, RG_MEMBASE		// r3 is the first parameter to vm->systemCalls
   1284 "    stwu	r12,4(r3)		\n"	// RG_TOP, 4(r3)
   1285 
   1286     // make the system call with the address of all the VM parms as a parameter
   1287     // vm->systemCalls( &parms )
   1288 "    lwz		r12,4(r10)	\n"	// RG_TOP, VM_OFFSET_SYSTEM_CALL(RG_VM)
   1289 "    mtctr	r12			\n"	// RG_TOP
   1290 "    bcctrl	20,0			\n"
   1291 "    mr		r12,r3			\n"	// RG_TOP, r3
   1292 
   1293     // pop our saved registers
   1294 "   	lwz		r3,56(r1)	\n"	// RG_STACK, 0(RG_REAL_STACK)
   1295 "   	lwz		r4,60(r1)	\n"	// RG_OPSTACK, 4(RG_REAL_STACK)
   1296 "   	lwz		r5,64(r1)	\n"	// RG_MEMBASE, 8(RG_REAL_STACK)
   1297 "   	lwz		r6,68(r1)	\n"	// RG_MEMMASK, 12(RG_REAL_STACK)
   1298 "   	lwz		r7,72(r1)	\n"	// RG_ASMCALL, 16(RG_REAL_STACK)
   1299 "   	lwz		r8,76(r1)	\n"	// RG_INSTRUCTIONS, 20(RG_REAL_STACK)
   1300 "   	lwz		r9,80(r1)	\n"	// RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
   1301 "   	lwz		r10,84(r1)	\n"	// RG_VM, 28(RG_REAL_STACK)
   1302 "   	lwz		r13,88(r1)	\n"	// RG_SECOND, 32(RG_REAL_STACK)
   1303 "    addi	r1,r1,92		\n"	// RG_REAL_STACK, RG_REAL_STACK, 36
   1304 
   1305     // restore the old link register
   1306 "    mtlr	r13			\n"	// RG_SECOND
   1307 
   1308     // save off the return value
   1309 "    stwu	r12,4(r4)		\n"	// RG_TOP, 0(RG_OPSTACK)
   1310 
   1311 	// GCC adds its own prolog / epilog code
   1312  );
   1313 }
   1314 #else
   1315 
   1316 // codewarrior version
   1317 
   1318 void asm AsmCall( void ) {
   1319 
   1320     // pop off the destination instruction
   1321 
   1322     lwz		r12,0(r4)	// RG_TOP, 0(RG_OPSTACK)
   1323 
   1324     addi	r4,r4,-4	// RG_OPSTACK, RG_OPSTACK, -4
   1325 
   1326 
   1327 
   1328     // see if it is a system trap
   1329 
   1330     cmpwi	r12,0		// RG_TOP, 0
   1331 
   1332     bc		12,0, systemTrap
   1333 
   1334 
   1335 
   1336     // calling another VM function, so lookup in instructionPointers
   1337 
   1338     slwi	r12,r12,2		// RG_TOP,RG_TOP,2
   1339 
   1340                         // FIXME: range check
   1341 
   1342     lwzx	r12, r8, r12	// RG_TOP, RG_INSTRUCTIONS(RG_TOP)	
   1343 
   1344     mtctr	r12			// RG_TOP
   1345 
   1346 
   1347 
   1348     bcctr	20,0		// when it hits a leave, it will branch to the current link register
   1349 
   1350 
   1351 
   1352     // calling a system trap
   1353 
   1354 systemTrap:
   1355 
   1356 	// convert to positive system call number
   1357 
   1358 	subfic	r12,r12,-1
   1359 
   1360 
   1361 
   1362     // save all our registers, including the current link register
   1363 
   1364     mflr	r13			// RG_SECOND		// copy off our link register
   1365 
   1366 	addi	r1,r1,-92	// required 24 byets of linkage, 32 bytes of parameter, plus our saves
   1367 
   1368     stw		r3,56(r1)	// RG_STACK, -36(REAL_STACK)
   1369 
   1370     stw		r4,60(r1)	// RG_OPSTACK, 4(RG_REAL_STACK)
   1371 
   1372     stw		r5,64(r1)	// RG_MEMBASE, 8(RG_REAL_STACK)
   1373 
   1374     stw		r6,68(r1)	// RG_MEMMASK, 12(RG_REAL_STACK)
   1375 
   1376     stw		r7,72(r1)	// RG_ASMCALL, 16(RG_REAL_STACK)
   1377 
   1378     stw		r8,76(r1)	// RG_INSTRUCTIONS, 20(RG_REAL_STACK)
   1379 
   1380     stw		r9,80(r1)	// RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
   1381 
   1382     stw		r10,84(r1)	// RG_VM, 28(RG_REAL_STACK)
   1383 
   1384     stw		r13,88(r1)	// RG_SECOND, 32(RG_REAL_STACK)	// link register
   1385 
   1386 
   1387 
   1388     // save the vm stack position to allow recursive VM entry
   1389 
   1390     addi	r13,r3,-4	// RG_TOP, RG_STACK, -4
   1391 
   1392     stw		r13,0(r10)	//RG_TOP, VM_OFFSET_PROGRAM_STACK(RG_VM)
   1393 
   1394 
   1395 
   1396     // save the system call number as the 0th parameter
   1397 
   1398     add		r3,r3,r5	// r3,  RG_STACK, RG_MEMBASE		// r3 is the first parameter to vm->systemCalls
   1399 
   1400     stwu	r12,4(r3)	// RG_TOP, 4(r3)
   1401 
   1402 
   1403 
   1404     // make the system call with the address of all the VM parms as a parameter
   1405 
   1406     // vm->systemCalls( &parms )
   1407 
   1408     lwz		r12,4(r10)	// RG_TOP, VM_OFFSET_SYSTEM_CALL(RG_VM)
   1409 
   1410     
   1411 
   1412     // perform macos cross fragment fixup crap
   1413 
   1414     lwz		r9,0(r12)
   1415 
   1416     stw		r2,52(r1)	// save old TOC
   1417 
   1418 	lwz		r2,4(r12)
   1419 
   1420 	    
   1421 
   1422     mtctr	r9			// RG_TOP
   1423 
   1424     bcctrl	20,0
   1425 
   1426     
   1427 
   1428     lwz		r2,52(r1)	// restore TOC
   1429 
   1430     
   1431 
   1432     mr		r12,r3		// RG_TOP, r3
   1433 
   1434 
   1435 
   1436     // pop our saved registers
   1437 
   1438    	lwz		r3,56(r1)	// RG_STACK, 0(RG_REAL_STACK)
   1439 
   1440    	lwz		r4,60(r1)	// RG_OPSTACK, 4(RG_REAL_STACK)
   1441 
   1442    	lwz		r5,64(r1)	// RG_MEMBASE, 8(RG_REAL_STACK)
   1443 
   1444    	lwz		r6,68(r1)	// RG_MEMMASK, 12(RG_REAL_STACK)
   1445 
   1446    	lwz		r7,72(r1)	// RG_ASMCALL, 16(RG_REAL_STACK)
   1447 
   1448    	lwz		r8,76(r1)	// RG_INSTRUCTIONS, 20(RG_REAL_STACK)
   1449 
   1450    	lwz		r9,80(r1)	// RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
   1451 
   1452    	lwz		r10,84(r1)	// RG_VM, 28(RG_REAL_STACK)
   1453 
   1454    	lwz		r13,88(r1)	// RG_SECOND, 32(RG_REAL_STACK)
   1455 
   1456     addi	r1,r1,92	// RG_REAL_STACK, RG_REAL_STACK, 36
   1457 
   1458 
   1459 
   1460     // restore the old link register
   1461 
   1462     mtlr	r13			// RG_SECOND
   1463 
   1464 
   1465 
   1466     // save off the return value
   1467 
   1468     stwu	r12,4(r4)	// RG_TOP, 0(RG_OPSTACK)
   1469 
   1470 
   1471 
   1472 	blr
   1473 
   1474 }
   1475 
   1476 
   1477 
   1478 
   1479 #endif