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