00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "vm_local.h"
00026
00027 #pragma opt_pointer_analysis off
00028
00029 #define DEBUG_VM 0
00030
00031 #if DEBUG_VM
00032 static char *opnames[256] = {
00033 "OP_UNDEF",
00034
00035 "OP_IGNORE",
00036
00037 "OP_BREAK",
00038
00039 "OP_ENTER",
00040 "OP_LEAVE",
00041 "OP_CALL",
00042 "OP_PUSH",
00043 "OP_POP",
00044
00045 "OP_CONST",
00046
00047 "OP_LOCAL",
00048
00049 "OP_JUMP",
00050
00051
00052
00053 "OP_EQ",
00054 "OP_NE",
00055
00056 "OP_LTI",
00057 "OP_LEI",
00058 "OP_GTI",
00059 "OP_GEI",
00060
00061 "OP_LTU",
00062 "OP_LEU",
00063 "OP_GTU",
00064 "OP_GEU",
00065
00066 "OP_EQF",
00067 "OP_NEF",
00068
00069 "OP_LTF",
00070 "OP_LEF",
00071 "OP_GTF",
00072 "OP_GEF",
00073
00074
00075
00076 "OP_LOAD1",
00077 "OP_LOAD2",
00078 "OP_LOAD4",
00079 "OP_STORE1",
00080 "OP_STORE2",
00081 "OP_STORE4",
00082 "OP_ARG",
00083
00084 "OP_BLOCK_COPY",
00085
00086
00087
00088 "OP_SEX8",
00089 "OP_SEX16",
00090
00091 "OP_NEGI",
00092 "OP_ADD",
00093 "OP_SUB",
00094 "OP_DIVI",
00095 "OP_DIVU",
00096 "OP_MODI",
00097 "OP_MODU",
00098 "OP_MULI",
00099 "OP_MULU",
00100
00101 "OP_BAND",
00102 "OP_BOR",
00103 "OP_BXOR",
00104 "OP_BCOM",
00105
00106 "OP_LSH",
00107 "OP_RSHI",
00108 "OP_RSHU",
00109
00110 "OP_NEGF",
00111 "OP_ADDF",
00112 "OP_SUBF",
00113 "OP_DIVF",
00114 "OP_MULF",
00115
00116 "OP_CVIF",
00117 "OP_CVFI"
00118 };
00119 #endif
00120
00121 typedef enum {
00122 R_REAL_STACK = 1,
00123
00124
00125
00126 R_STACK = 3,
00127 R_OPSTACK,
00128
00129
00130 R_MEMBASE,
00131 R_MEMMASK,
00132 R_ASMCALL,
00133 R_INSTRUCTIONS,
00134 R_NUM_INSTRUCTIONS,
00135 R_CVM,
00136
00137
00138 R_TOP = 11,
00139 R_SECOND = 12,
00140 R_EA = 2
00141
00142 } regNums_t;
00143
00144 #define RG_REAL_STACK r1
00145 #define RG_STACK r3
00146 #define RG_OPSTACK r4
00147 #define RG_MEMBASE r5
00148 #define RG_MEMMASK r6
00149 #define RG_ASMCALL r7
00150 #define RG_INSTRUCTIONS r8
00151 #define RG_NUM_INSTRUCTIONS r9
00152 #define RG_CVM r10
00153 #define RG_TOP r12
00154 #define RG_SECOND r13
00155 #define RG_EA r14
00156
00157
00158 #define OP_STACK_MAX_DEPTH 12
00159
00160
00161
00162 static int opStackIntRegisters[OP_STACK_MAX_DEPTH] =
00163 {
00164 16, 17, 18, 19,
00165 20, 21, 22, 23,
00166 24, 25, 26, 27
00167 };
00168
00169 static unsigned int *opStackLoadInstructionAddr[OP_STACK_MAX_DEPTH];
00170
00171
00172
00173 static int opStackFloatRegisters[OP_STACK_MAX_DEPTH] =
00174 {
00175 0, 1, 2, 3,
00176 4, 5, 6, 7,
00177 8, 9, 10, 11
00178 };
00179
00180 static int opStackRegType[OP_STACK_MAX_DEPTH] =
00181 {
00182 0, 0, 0, 0,
00183 0, 0, 0, 0,
00184 0, 0, 0, 0
00185 };
00186
00187
00188 typedef enum {
00189 PPC_TDI = 0x08000000,
00190 PPC_TWI = 0x0c000000,
00191 PPC_MULLI = 0x1c000000,
00192 PPC_SUBFIC = 0x20000000,
00193 PPC_CMPI = 0x28000000,
00194 PPC_CMPLI = 0x2c000000,
00195 PPC_ADDIC = 0x30000000,
00196 PPC_ADDIC_ = 0x34000000,
00197 PPC_ADDI = 0x38000000,
00198 PPC_ADDIS = 0x3c000000,
00199 PPC_BC = 0x40000000,
00200 PPC_SC = 0x44000000,
00201 PPC_B = 0x48000000,
00202
00203 PPC_MCRF = 0x4c000000,
00204 PPC_BCLR = 0x4c000020,
00205 PPC_RFID = 0x4c000000,
00206 PPC_CRNOR = 0x4c000000,
00207 PPC_RFI = 0x4c000000,
00208 PPC_CRANDC = 0x4c000000,
00209 PPC_ISYNC = 0x4c000000,
00210 PPC_CRXOR = 0x4c000000,
00211 PPC_CRNAND = 0x4c000000,
00212 PPC_CREQV = 0x4c000000,
00213 PPC_CRORC = 0x4c000000,
00214 PPC_CROR = 0x4c000000,
00215
00216 PPC_BCCTR = 0x4c000420,
00217 PPC_RLWIMI = 0x50000000,
00218 PPC_RLWINM = 0x54000000,
00219 PPC_RLWNM = 0x5c000000,
00220 PPC_ORI = 0x60000000,
00221 PPC_ORIS = 0x64000000,
00222 PPC_XORI = 0x68000000,
00223 PPC_XORIS = 0x6c000000,
00224 PPC_ANDI_ = 0x70000000,
00225 PPC_ANDIS_ = 0x74000000,
00226 PPC_RLDICL = 0x78000000,
00227 PPC_RLDICR = 0x78000000,
00228 PPC_RLDIC = 0x78000000,
00229 PPC_RLDIMI = 0x78000000,
00230 PPC_RLDCL = 0x78000000,
00231 PPC_RLDCR = 0x78000000,
00232 PPC_CMP = 0x7c000000,
00233 PPC_TW = 0x7c000000,
00234 PPC_SUBFC = 0x7c000010,
00235 PPC_MULHDU = 0x7c000000,
00236 PPC_ADDC = 0x7c000014,
00237 PPC_MULHWU = 0x7c000000,
00238 PPC_MFCR = 0x7c000000,
00239 PPC_LWAR = 0x7c000000,
00240 PPC_LDX = 0x7c000000,
00241 PPC_LWZX = 0x7c00002e,
00242 PPC_SLW = 0x7c000030,
00243 PPC_CNTLZW = 0x7c000000,
00244 PPC_SLD = 0x7c000000,
00245 PPC_AND = 0x7c000038,
00246 PPC_CMPL = 0x7c000040,
00247 PPC_SUBF = 0x7c000050,
00248 PPC_LDUX = 0x7c000000,
00249
00250 PPC_DCBST = 0x7c000000,
00251 PPC_LWZUX = 0x7c00006c,
00252 PPC_CNTLZD = 0x7c000000,
00253 PPC_ANDC = 0x7c000000,
00254 PPC_TD = 0x7c000000,
00255 PPC_MULHD = 0x7c000000,
00256 PPC_MULHW = 0x7c000000,
00257 PPC_MTSRD = 0x7c000000,
00258 PPC_MFMSR = 0x7c000000,
00259 PPC_LDARX = 0x7c000000,
00260 PPC_DCBF = 0x7c000000,
00261 PPC_LBZX = 0x7c0000ae,
00262 PPC_NEG = 0x7c000000,
00263 PPC_MTSRDIN = 0x7c000000,
00264 PPC_LBZUX = 0x7c000000,
00265 PPC_NOR = 0x7c0000f8,
00266 PPC_SUBFE = 0x7c000000,
00267 PPC_ADDE = 0x7c000000,
00268 PPC_MTCRF = 0x7c000000,
00269 PPC_MTMSR = 0x7c000000,
00270 PPC_STDX = 0x7c000000,
00271 PPC_STWCX_ = 0x7c000000,
00272 PPC_STWX = 0x7c00012e,
00273 PPC_MTMSRD = 0x7c000000,
00274 PPC_STDUX = 0x7c000000,
00275 PPC_STWUX = 0x7c00016e,
00276 PPC_SUBFZE = 0x7c000000,
00277 PPC_ADDZE = 0x7c000000,
00278 PPC_MTSR = 0x7c000000,
00279 PPC_STDCX_ = 0x7c000000,
00280 PPC_STBX = 0x7c0001ae,
00281 PPC_SUBFME = 0x7c000000,
00282 PPC_MULLD = 0x7c000000,
00283
00284 PPC_ADDME = 0x7c000000,
00285 PPC_MULLW = 0x7c0001d6,
00286 PPC_MTSRIN = 0x7c000000,
00287 PPC_DCBTST = 0x7c000000,
00288 PPC_STBUX = 0x7c000000,
00289 PPC_ADD = 0x7c000214,
00290 PPC_DCBT = 0x7c000000,
00291 PPC_LHZX = 0x7c00022e,
00292 PPC_EQV = 0x7c000000,
00293 PPC_TLBIE = 0x7c000000,
00294 PPC_ECIWX = 0x7c000000,
00295 PPC_LHZUX = 0x7c000000,
00296 PPC_XOR = 0x7c000278,
00297 PPC_MFSPR = 0x7c0002a6,
00298 PPC_LWAX = 0x7c000000,
00299 PPC_LHAX = 0x7c000000,
00300 PPC_TLBIA = 0x7c000000,
00301 PPC_MFTB = 0x7c000000,
00302 PPC_LWAUX = 0x7c000000,
00303 PPC_LHAUX = 0x7c000000,
00304 PPC_STHX = 0x7c00032e,
00305 PPC_ORC = 0x7c000338,
00306 PPC_SRADI = 0x7c000000,
00307 PPC_SLBIE = 0x7c000000,
00308 PPC_ECOWX = 0x7c000000,
00309 PPC_STHUX = 0x7c000000,
00310 PPC_OR = 0x7c000378,
00311 PPC_DIVDU = 0x7c000000,
00312 PPC_DIVWU = 0x7c000396,
00313 PPC_MTSPR = 0x7c0003a6,
00314 PPC_DCBI = 0x7c000000,
00315 PPC_NAND = 0x7c000000,
00316 PPC_DIVD = 0x7c000000,
00317
00318 PPC_DIVW = 0x7c0003d6,
00319 PPC_SLBIA = 0x7c000000,
00320 PPC_MCRXR = 0x7c000000,
00321 PPC_LSWX = 0x7c000000,
00322 PPC_LWBRX = 0x7c000000,
00323 PPC_LFSX = 0x7c00042e,
00324 PPC_SRW = 0x7c000430,
00325 PPC_SRD = 0x7c000000,
00326 PPC_TLBSYNC = 0x7c000000,
00327 PPC_LFSUX = 0x7c000000,
00328 PPC_MFSR = 0x7c000000,
00329 PPC_LSWI = 0x7c000000,
00330 PPC_SYNC = 0x7c000000,
00331 PPC_LFDX = 0x7c000000,
00332 PPC_LFDUX = 0x7c000000,
00333 PPC_MFSRIN = 0x7c000000,
00334 PPC_STSWX = 0x7c000000,
00335 PPC_STWBRX = 0x7c000000,
00336 PPC_STFSX = 0x7c00052e,
00337 PPC_STFSUX = 0x7c000000,
00338 PPC_STSWI = 0x7c000000,
00339 PPC_STFDX = 0x7c000000,
00340 PPC_DCBA = 0x7c000000,
00341 PPC_STFDUX = 0x7c000000,
00342 PPC_LHBRX = 0x7c000000,
00343 PPC_SRAW = 0x7c000630,
00344 PPC_SRAD = 0x7c000000,
00345 PPC_SRAWI = 0x7c000000,
00346 PPC_EIEIO = 0x7c000000,
00347 PPC_STHBRX = 0x7c000000,
00348 PPC_EXTSH = 0x7c000734,
00349 PPC_EXTSB = 0x7c000774,
00350 PPC_ICBI = 0x7c000000,
00351
00352 PPC_STFIWX = 0x7c0007ae,
00353 PPC_EXTSW = 0x7c000000,
00354 PPC_DCBZ = 0x7c000000,
00355 PPC_LWZ = 0x80000000,
00356 PPC_LWZU = 0x84000000,
00357 PPC_LBZ = 0x88000000,
00358 PPC_LBZU = 0x8c000000,
00359 PPC_STW = 0x90000000,
00360 PPC_STWU = 0x94000000,
00361 PPC_STB = 0x98000000,
00362 PPC_STBU = 0x9c000000,
00363 PPC_LHZ = 0xa0000000,
00364 PPC_LHZU = 0xa4000000,
00365 PPC_LHA = 0xa8000000,
00366 PPC_LHAU = 0xac000000,
00367 PPC_STH = 0xb0000000,
00368 PPC_STHU = 0xb4000000,
00369 PPC_LMW = 0xb8000000,
00370 PPC_STMW = 0xbc000000,
00371 PPC_LFS = 0xc0000000,
00372 PPC_LFSU = 0xc4000000,
00373 PPC_LFD = 0xc8000000,
00374 PPC_LFDU = 0xcc000000,
00375 PPC_STFS = 0xd0000000,
00376 PPC_STFSU = 0xd4000000,
00377 PPC_STFD = 0xd8000000,
00378 PPC_STFDU = 0xdc000000,
00379 PPC_LD = 0xe8000000,
00380 PPC_LDU = 0xe8000001,
00381 PPC_LWA = 0xe8000002,
00382 PPC_FDIVS = 0xec000024,
00383 PPC_FSUBS = 0xec000028,
00384 PPC_FADDS = 0xec00002a,
00385
00386 PPC_FSQRTS = 0xec000000,
00387 PPC_FRES = 0xec000000,
00388 PPC_FMULS = 0xec000032,
00389 PPC_FMSUBS = 0xec000000,
00390 PPC_FMADDS = 0xec000000,
00391 PPC_FNMSUBS = 0xec000000,
00392 PPC_FNMADDS = 0xec000000,
00393 PPC_STD = 0xf8000000,
00394 PPC_STDU = 0xf8000001,
00395 PPC_FCMPU = 0xfc000000,
00396 PPC_FRSP = 0xfc000018,
00397 PPC_FCTIW = 0xfc000000,
00398 PPC_FCTIWZ = 0xfc00001e,
00399 PPC_FDIV = 0xfc000000,
00400 PPC_FSUB = 0xfc000028,
00401 PPC_FADD = 0xfc000000,
00402 PPC_FSQRT = 0xfc000000,
00403 PPC_FSEL = 0xfc000000,
00404 PPC_FMUL = 0xfc000000,
00405 PPC_FRSQRTE = 0xfc000000,
00406 PPC_FMSUB = 0xfc000000,
00407 PPC_FMADD = 0xfc000000,
00408 PPC_FNMSUB = 0xfc000000,
00409 PPC_FNMADD = 0xfc000000,
00410 PPC_FCMPO = 0xfc000000,
00411 PPC_MTFSB1 = 0xfc000000,
00412 PPC_FNEG = 0xfc000050,
00413 PPC_MCRFS = 0xfc000000,
00414 PPC_MTFSB0 = 0xfc000000,
00415 PPC_FMR = 0xfc000000,
00416 PPC_MTFSFI = 0xfc000000,
00417 PPC_FNABS = 0xfc000000,
00418 PPC_FABS = 0xfc000000,
00419
00420 PPC_MFFS = 0xfc000000,
00421 PPC_MTFSF = 0xfc000000,
00422 PPC_FCTID = 0xfc000000,
00423 PPC_FCTIDZ = 0xfc000000,
00424 PPC_FCFID = 0xfc000000
00425
00426 } ppcOpcodes_t;
00427
00428
00429
00430 static unsigned *buf;
00431 static int compiledOfs;
00432 static int pass;
00433
00434
00435 static byte *code;
00436 static int pc;
00437
00438 void AsmCall( void );
00439
00440 double itofConvert[2];
00441
00442 static int Constant4( void ) {
00443 int v;
00444
00445 v = code[pc] | (code[pc+1]<<8) | (code[pc+2]<<16) | (code[pc+3]<<24);
00446 pc += 4;
00447 return v;
00448 }
00449
00450 static int Constant1( void ) {
00451 int v;
00452
00453 v = code[pc];
00454 pc += 1;
00455 return v;
00456 }
00457
00458 static void Emit4( char *opname, int i ) {
00459 #if DEBUG_VM
00460 if(pass == 1)
00461 printf("\t\t\t%p %s\t%08lx\n",&buf[compiledOfs],opname,i&0x3ffffff);
00462 #endif
00463 buf[ compiledOfs ] = i;
00464 compiledOfs++;
00465 }
00466
00467 static void Inst( char *opname, int opcode, int destReg, int aReg, int bReg ) {
00468 unsigned r;
00469
00470 #if DEBUG_VM
00471 if(pass == 1)
00472 printf("\t\t\t%p %s\tr%d,r%d,r%d\n",&buf[compiledOfs],opname,destReg,aReg,bReg);
00473 #endif
00474 r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) ;
00475 buf[ compiledOfs ] = r;
00476 compiledOfs++;
00477 }
00478
00479 static void Inst4( char *opname, int opcode, int destReg, int aReg, int bReg, int cReg ) {
00480 unsigned r;
00481
00482 #if DEBUG_VM
00483 if(pass == 1)
00484 printf("\t\t\t%p %s\tr%d,r%d,r%d,r%d\n",&buf[compiledOfs],opname,destReg,aReg,bReg,cReg);
00485 #endif
00486 r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) | ( cReg << 6 );
00487 buf[ compiledOfs ] = r;
00488 compiledOfs++;
00489 }
00490
00491 static void InstImm( char *opname, int opcode, int destReg, int aReg, int immediate ) {
00492 unsigned r;
00493
00494 if ( immediate > 32767 || immediate < -32768 ) {
00495 Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range, opcode %x,%d,%d", immediate, opcode, destReg, aReg );
00496 }
00497 #if DEBUG_VM
00498 if(pass == 1)
00499 printf("\t\t\t%p %s\tr%d,r%d,0x%x\n",&buf[compiledOfs],opname,destReg,aReg,immediate);
00500 #endif
00501 r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff );
00502 buf[ compiledOfs ] = r;
00503 compiledOfs++;
00504 }
00505
00506 static void InstImmU( char *opname, int opcode, int destReg, int aReg, int immediate ) {
00507 unsigned r;
00508
00509 if ( immediate > 0xffff || immediate < 0 ) {
00510 Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range", immediate );
00511 }
00512 #if DEBUG_VM
00513 if(pass == 1)
00514 printf("\t\t\t%p %s\tr%d,r%d,0x%x\n",&buf[compiledOfs],opname,destReg,aReg,immediate);
00515 #endif
00516 r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff );
00517 buf[ compiledOfs ] = r;
00518 compiledOfs++;
00519 }
00520
00521 static int pop0, pop1, oc0, oc1;
00522 static vm_t *tvm;
00523 static int instruction;
00524 static byte *jused;
00525
00526 static void ltop() {
00527
00528
00529
00530 }
00531
00532 static void ltopandsecond() {
00533 #if 0
00534 if (pass>=0 && buf[compiledOfs-1] == (PPC_STWU | R_TOP<<21 | R_OPSTACK<<16 | 4 ) && jused[instruction]==0 ) {
00535 compiledOfs--;
00536 if (!pass) {
00537 tvm->instructionPointers[instruction] = compiledOfs * 4;
00538 }
00539 InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 );
00540 InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
00541 } else if (pass>=0 && buf[compiledOfs-1] == (PPC_STW | R_TOP<<21 | R_OPSTACK<<16 | 0 ) && jused[instruction]==0 ) {
00542 compiledOfs--;
00543 if (!pass) {
00544 tvm->instructionPointers[instruction] = compiledOfs * 4;
00545 }
00546 InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, -4 );
00547 InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 );
00548 } else {
00549 ltop();
00550 InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, -4 );
00551 InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 );
00552 }
00553 rtopped = qfalse;
00554 #endif
00555 }
00556
00557 static void spillOpStack(int depth)
00558 {
00559
00560 int i;
00561
00562 for(i = 0; i < depth; i++)
00563 {
00564 assert(opStackRegType[i]);
00565 assert(opStackRegType[i] == 1);
00566 switch(opStackRegType[i])
00567 {
00568 case 1:
00569 InstImm( "stw", PPC_STW, opStackIntRegisters[i], R_OPSTACK, i*4+4);
00570 break;
00571 case 2:
00572 InstImm( "stfs", PPC_STFS, opStackFloatRegisters[i], R_OPSTACK, i*4+4);
00573 break;
00574 }
00575 opStackRegType[i] = 0;
00576 }
00577 }
00578
00579 static void loadOpStack(int depth)
00580 {
00581
00582
00583
00584 int i;
00585
00586 for(i = 0; i < depth; i++)
00587 {
00588 assert(opStackRegType[i] == 0);
00589
00590 opStackLoadInstructionAddr[i] = &buf[compiledOfs];
00591 InstImm( "lwz", PPC_LWZ, opStackIntRegisters[i], R_OPSTACK, i*4+4);
00592 opStackRegType[i] = 1;
00593 }
00594 }
00595
00596 static void makeInteger(int depth)
00597 {
00598
00599 assert(opStackRegType[depth] == 1);
00600
00601 if(opStackRegType[depth] == 2)
00602 {
00603 unsigned instruction;
00604 assert(opStackLoadInstructionAddr[depth]);
00605
00606 printf("patching float load at %p to int load\n",opStackLoadInstructionAddr[depth]);
00607
00608 instruction = *opStackLoadInstructionAddr[depth];
00609 instruction &= ~PPC_LFSX;
00610 instruction |= PPC_LWZX;
00611 *opStackLoadInstructionAddr[depth] = instruction;
00612 opStackLoadInstructionAddr[depth] = 0;
00613 opStackRegType[depth] = 1;
00614 #if 0
00615 InstImm( "stfs", PPC_STFS, opStackFloatRegisters[depth], R_OPSTACK, depth*4+4);
00616
00617
00618 Inst( "ori", PPC_ORI, 0, 0, 0 );
00619 Inst( "ori", PPC_ORI, 0, 0, 0 );
00620 Inst( "ori", PPC_ORI, 0, 0, 0 );
00621 Inst( "ori", PPC_ORI, 0, 0, 0 );
00622 InstImm( "lwz", PPC_LWZ, opStackIntRegisters[depth], R_OPSTACK, depth*4+4);
00623 opStackRegType[depth] = 1;
00624 #endif
00625 }
00626 }
00627
00628 static void makeFloat(int depth)
00629 {
00630
00631 if(opStackRegType[depth] == 1)
00632 {
00633 unsigned instruction;
00634 unsigned destReg, aReg, bReg, imm;
00635
00636 if(opStackLoadInstructionAddr[depth])
00637 {
00638
00639 instruction = *opStackLoadInstructionAddr[depth];
00640
00641 if((instruction & 0xfc000000) == PPC_LWZ)
00642 {
00643
00644
00645
00646 destReg = (instruction >> 21) & 31;
00647 aReg = (instruction >> 16) & 31;
00648 imm = instruction & 0xffff;
00649
00650
00651
00652
00653 destReg = (destReg - opStackIntRegisters[0]) + opStackFloatRegisters[0];
00654 instruction = PPC_LFS | ( destReg << 21 ) | ( aReg << 16 ) | imm ;
00655
00656
00657 }
00658 else
00659 {
00660
00661
00662
00663 destReg = (instruction >> 21) & 31;
00664 aReg = (instruction >> 16) & 31;
00665 bReg = (instruction >> 11) & 31;
00666
00667
00668
00669 destReg = (destReg - opStackIntRegisters[0]) + opStackFloatRegisters[0];
00670 instruction = PPC_LFSX | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) ;
00671
00672
00673 }
00674 *opStackLoadInstructionAddr[depth] = instruction;
00675 opStackLoadInstructionAddr[depth] = 0;
00676 }
00677 else
00678 {
00679
00680
00681
00682
00683 InstImm( "stw", PPC_STW, opStackIntRegisters[depth], R_OPSTACK, depth*4+4);
00684
00685
00686 Inst( "ori", PPC_ORI, 0, 0, 0 );
00687 Inst( "ori", PPC_ORI, 0, 0, 0 );
00688 Inst( "ori", PPC_ORI, 0, 0, 0 );
00689 Inst( "ori", PPC_ORI, 0, 0, 0 );
00690 InstImm( "lfs", PPC_LFS, opStackFloatRegisters[depth], R_OPSTACK, depth*4+4);
00691 }
00692 opStackRegType[depth] = 2;
00693 }
00694 }
00695
00696
00697 #if 0
00698 static void fltop() {
00699 if (rtopped == qfalse) {
00700 InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 );
00701 }
00702 }
00703 #endif
00704
00705 #if 0
00706 static void fltopandsecond() {
00707 InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 );
00708 InstImm( PPC_LFS, R_SECOND, R_OPSTACK, -4 );
00709 InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 );
00710 rtopped = qfalse;
00711 return;
00712 }
00713 #endif
00714
00715 #define assertInteger(depth) assert(opStackRegType[depth] == 1)
00716
00717
00718
00719
00720
00721
00722 void VM_Compile( vm_t *vm, vmHeader_t *header ) {
00723 int op;
00724 int maxLength;
00725 int v;
00726 int i;
00727 int opStackDepth;
00728
00729 int mainFunction;
00730
00731
00732 ((int *)itofConvert)[0] = 0x43300000;
00733 ((int *)itofConvert)[1] = 0x80000000;
00734 ((int *)itofConvert)[2] = 0x43300000;
00735
00736
00737 maxLength = header->codeLength * 8;
00738 buf = Z_Malloc( maxLength );
00739 jused = Z_Malloc(header->instructionCount + 2);
00740 Com_Memset(jused, 0, header->instructionCount+2);
00741
00742
00743
00744 for ( pass = -1 ; pass < 2 ; pass++ ) {
00745
00746
00747 pc = 0;
00748 mainFunction = 0;
00749 opStackDepth = 0;
00750
00751 pop0 = 343545;
00752 pop1 = 2443545;
00753 oc0 = -2343535;
00754 oc1 = 24353454;
00755 tvm = vm;
00756 code = (byte *)header + header->codeOffset;
00757 compiledOfs = 0;
00758 #ifndef __GNUC__
00759
00760 Emit4( (int)(buf+2) );
00761 Emit4( 0 );
00762 #endif
00763
00764 for ( instruction = 0 ; instruction < header->instructionCount ; instruction++ ) {
00765 if ( compiledOfs*4 > maxLength - 16 ) {
00766 Com_Error( ERR_DROP, "VM_Compile: maxLength exceeded" );
00767 }
00768
00769 op = code[ pc ];
00770 if ( !pass ) {
00771 vm->instructionPointers[ instruction ] = compiledOfs * 4;
00772 }
00773 pc++;
00774 switch ( op ) {
00775 case 0:
00776 break;
00777 case OP_BREAK:
00778 #if DEBUG_VM
00779 if(pass == 1)
00780 printf("%08lx BREAK\n",instruction);
00781 #endif
00782 InstImmU( "addi", PPC_ADDI, R_TOP, 0, 0 );
00783 InstImm( "lwz", PPC_LWZ, R_TOP, R_TOP, 0 );
00784 break;
00785 case OP_ENTER:
00786 opStackDepth = 0;
00787 v = Constant4();
00788 #if DEBUG_VM
00789 if(pass == 1)
00790 printf("%08x ENTER\t%04x\n",instruction,v);
00791 #endif
00792 opStackRegType[opStackDepth] = 0;
00793 mainFunction++;
00794 if(mainFunction == 1)
00795 {
00796
00797
00798
00799 InstImm( "addi", PPC_ADDI, R_REAL_STACK, R_REAL_STACK, -OP_STACK_MAX_DEPTH*4 );
00800 for(i = 0; i < OP_STACK_MAX_DEPTH; i++)
00801 InstImm( "stw", PPC_STW, opStackIntRegisters[i], R_REAL_STACK, i*4);
00802 }
00803 InstImm( "addi", PPC_ADDI, R_STACK, R_STACK, -v );
00804 break;
00805 case OP_CONST:
00806 v = Constant4();
00807 #if DEBUG_VM
00808 if(pass == 1)
00809 printf("%08x CONST\t%08x\n",instruction,v);
00810 #endif
00811 opStackLoadInstructionAddr[opStackDepth] = 0;
00812 if ( v < 32768 && v >= -32768 ) {
00813 InstImmU( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth], 0, v & 0xffff );
00814 } else {
00815 InstImmU( "addis", PPC_ADDIS, opStackIntRegisters[opStackDepth], 0, (v >> 16)&0xffff );
00816 if ( v & 0xffff ) {
00817 InstImmU( "ori", PPC_ORI, opStackIntRegisters[opStackDepth], opStackIntRegisters[opStackDepth], v & 0xffff );
00818 }
00819 }
00820 opStackRegType[opStackDepth] = 1;
00821 opStackDepth += 1;
00822 if (code[pc] == OP_JUMP) {
00823 jused[v] = 1;
00824 }
00825 break;
00826 case OP_LOCAL:
00827 oc1 = Constant4();
00828 #if DEBUG_VM
00829 if(pass == 1)
00830 printf("%08x LOCAL\t%08x\n",instruction,oc1);
00831 #endif
00832 if (code[pc] == OP_LOAD4 || code[pc] == OP_LOAD2 || code[pc] == OP_LOAD1) {
00833 oc1 &= vm->dataMask;
00834 }
00835 InstImm( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth], R_STACK, oc1 );
00836 opStackRegType[opStackDepth] = 1;
00837 opStackLoadInstructionAddr[opStackDepth] = 0;
00838 opStackDepth += 1;
00839 break;
00840 case OP_ARG:
00841 v = Constant1();
00842 #if DEBUG_VM
00843 if(pass == 1)
00844 printf("%08x ARG \t%08x\n",instruction,v);
00845 #endif
00846 InstImm( "addi", PPC_ADDI, R_EA, R_STACK, v );
00847 if(opStackRegType[opStackDepth-1] == 1)
00848 Inst( "stwx", PPC_STWX, opStackIntRegisters[opStackDepth-1], R_EA, R_MEMBASE );
00849 else
00850 Inst( "stfsx", PPC_STFSX, opStackFloatRegisters[opStackDepth-1], R_EA, R_MEMBASE );
00851 opStackRegType[opStackDepth-1] = 0;
00852 opStackLoadInstructionAddr[opStackDepth-1] = 0;
00853 opStackDepth -= 1;
00854
00855 break;
00856 case OP_CALL:
00857 #if DEBUG_VM
00858 if(pass == 1)
00859 printf("%08x CALL\n",instruction);
00860 #endif
00861 assertInteger(opStackDepth-1);
00862 assert(opStackDepth > 0);
00863 Inst( "mflr", PPC_MFSPR, R_SECOND, 8, 0 );
00864 InstImm( "stwu", PPC_STWU, R_SECOND, R_REAL_STACK, -16 );
00865
00866
00867 spillOpStack(opStackDepth);
00868
00869
00870
00871 InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, opStackDepth*4);
00872
00873 Inst( "mtctr", PPC_MTSPR, R_ASMCALL, 9, 0 );
00874 Inst( "bctrl", PPC_BCCTR | 1, 20, 0, 0 );
00875
00876
00877
00878
00879 InstImm("addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, -opStackDepth*4);
00880
00881
00882 loadOpStack(opStackDepth);
00883
00884 InstImm( "lwz", PPC_LWZ, R_SECOND, R_REAL_STACK, 0 );
00885 InstImm( "addi", PPC_ADDI, R_REAL_STACK, R_REAL_STACK, 16 );
00886 Inst( "mtlr", PPC_MTSPR, R_SECOND, 8, 0 );
00887 break;
00888 case OP_PUSH:
00889 #if DEBUG_VM
00890 if(pass == 1)
00891 printf("%08x PUSH\n",instruction);
00892 #endif
00893 opStackRegType[opStackDepth] = 1;
00894 opStackDepth += 1;
00895 break;
00896 case OP_POP:
00897 #if DEBUG_VM
00898 if(pass == 1)
00899 printf("%08x POP\n",instruction);
00900 #endif
00901 opStackDepth -= 1;
00902 opStackRegType[opStackDepth] = 0;
00903 opStackLoadInstructionAddr[opStackDepth-1] = 0;
00904 break;
00905 case OP_LEAVE:
00906 #if DEBUG_VM
00907 if(pass == 1)
00908 printf("%08x LEAVE\n",instruction);
00909 #endif
00910 assert(opStackDepth == 1);
00911 assert(opStackRegType[0] != 0);
00912
00913 switch(opStackRegType[0])
00914 {
00915 case 1:
00916 InstImm( "stw", PPC_STWU, opStackIntRegisters[0], R_OPSTACK, 4);
00917 break;
00918 case 2:
00919 InstImm( "stfs", PPC_STFSU, opStackFloatRegisters[0], R_OPSTACK, 4);
00920 break;
00921 }
00922 InstImm( "addi", PPC_ADDI, R_STACK, R_STACK, Constant4() );
00923 if(mainFunction == 1)
00924 {
00925 for(i = 0; i < OP_STACK_MAX_DEPTH; i++)
00926 InstImm( "lwz", PPC_LWZ, opStackIntRegisters[i], R_REAL_STACK, i*4);
00927 InstImm( "addi", PPC_ADDI, R_REAL_STACK, R_REAL_STACK, OP_STACK_MAX_DEPTH*4 );
00928 }
00929 opStackDepth--;
00930 opStackRegType[opStackDepth] = 0;
00931 opStackLoadInstructionAddr[opStackDepth] = 0;
00932 Inst( "blr", PPC_BCLR, 20, 0, 0 );
00933 break;
00934 case OP_LOAD4:
00935 #if DEBUG_VM
00936 if(pass == 1)
00937 printf("%08x LOAD4\n",instruction);
00938 #endif
00939
00940
00941
00942
00943
00944
00945 assertInteger(opStackDepth-1);
00946 opStackLoadInstructionAddr[opStackDepth-1] = &buf[ compiledOfs ];
00947 Inst( "lwzx", PPC_LWZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );
00948 opStackRegType[opStackDepth-1] = 1;
00949 break;
00950 case OP_LOAD2:
00951 #if DEBUG_VM
00952 if(pass == 1)
00953 printf("%08x LOAD2\n",instruction);
00954 #endif
00955 assertInteger(opStackDepth-1);
00956 opStackLoadInstructionAddr[opStackDepth-1] = 0;
00957 Inst( "lhzx", PPC_LHZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );
00958 opStackRegType[opStackDepth-1] = 1;
00959 break;
00960 case OP_LOAD1:
00961 #if DEBUG_VM
00962 if(pass == 1)
00963 printf("%08x LOAD1\n",instruction);
00964 #endif
00965 assertInteger(opStackDepth-1);
00966 opStackLoadInstructionAddr[opStackDepth-1] = 0;
00967 Inst( "lbzx", PPC_LBZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );
00968 opStackRegType[opStackDepth-1] = 1;
00969 break;
00970 case OP_STORE4:
00971 #if DEBUG_VM
00972 if(pass == 1)
00973 printf("%08x STORE4\n",instruction);
00974 #endif
00975 assertInteger(opStackDepth-2);
00976 if(opStackRegType[opStackDepth-1] == 1)
00977 Inst( "stwx", PPC_STWX, opStackIntRegisters[opStackDepth-1],
00978 opStackIntRegisters[opStackDepth-2], R_MEMBASE );
00979 else
00980 Inst( "stfsx", PPC_STFSX, opStackFloatRegisters[opStackDepth-1],
00981 opStackIntRegisters[opStackDepth-2], R_MEMBASE );
00982 opStackRegType[opStackDepth-1] = 0;
00983 opStackRegType[opStackDepth-2] = 0;
00984 opStackLoadInstructionAddr[opStackDepth-1] = 0;
00985 opStackLoadInstructionAddr[opStackDepth-2] = 0;
00986 opStackDepth -= 2;
00987 break;
00988 case OP_STORE2:
00989 #if DEBUG_VM
00990 if(pass == 1)
00991 printf("%08x STORE2\n",instruction);
00992 #endif
00993 assertInteger(opStackDepth-1);
00994 assertInteger(opStackDepth-2);
00995 Inst( "sthx", PPC_STHX, opStackIntRegisters[opStackDepth-1],
00996 opStackIntRegisters[opStackDepth-2], R_MEMBASE );
00997 opStackRegType[opStackDepth-1] = 0;
00998 opStackRegType[opStackDepth-2] = 0;
00999 opStackLoadInstructionAddr[opStackDepth-1] = 0;
01000 opStackLoadInstructionAddr[opStackDepth-2] = 0;
01001 opStackDepth -= 2;
01002 break;
01003 case OP_STORE1:
01004 #if DEBUG_VM
01005 if(pass == 1)
01006 printf("%08x STORE1\n",instruction);
01007 #endif
01008 assertInteger(opStackDepth-1);
01009 assertInteger(opStackDepth-2);
01010 Inst( "stbx", PPC_STBX, opStackIntRegisters[opStackDepth-1],
01011 opStackIntRegisters[opStackDepth-2], R_MEMBASE );
01012 opStackRegType[opStackDepth-1] = 0;
01013 opStackRegType[opStackDepth-2] = 0;
01014 opStackLoadInstructionAddr[opStackDepth-1] = 0;
01015 opStackLoadInstructionAddr[opStackDepth-2] = 0;
01016 opStackDepth -= 2;
01017 break;
01018
01019 case OP_EQ:
01020 #if DEBUG_VM
01021 if(pass == 1)
01022 printf("%08x EQ\n",instruction);
01023 #endif
01024 assertInteger(opStackDepth-1);
01025 assertInteger(opStackDepth-2);
01026 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01027 opStackRegType[opStackDepth-1] = 0;
01028 opStackRegType[opStackDepth-2] = 0;
01029 opStackLoadInstructionAddr[opStackDepth-1] = 0;
01030 opStackLoadInstructionAddr[opStackDepth-2] = 0;
01031 opStackDepth -= 2;
01032 i = Constant4();
01033 jused[i] = 1;
01034 InstImm( "bc", PPC_BC, 4, 2, 8 );
01035 if ( pass==1 ) {
01036 v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01037 } else {
01038 v = 0;
01039 }
01040 Emit4("b", PPC_B | (v&0x3ffffff) );
01041 break;
01042 case OP_NE:
01043 #if DEBUG_VM
01044 if(pass == 1)
01045 printf("%08x NE\n",instruction);
01046 #endif
01047 assertInteger(opStackDepth-1);
01048 assertInteger(opStackDepth-2);
01049 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01050 opStackRegType[opStackDepth-1] = 0;
01051 opStackRegType[opStackDepth-2] = 0;
01052 opStackLoadInstructionAddr[opStackDepth-1] = 0;
01053 opStackLoadInstructionAddr[opStackDepth-2] = 0;
01054 opStackDepth -= 2;
01055 i = Constant4();
01056 jused[i] = 1;
01057 InstImm( "bc", PPC_BC, 12, 2, 8 );
01058 if ( pass==1 ) {
01059 v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01060 } else {
01061 v = 0;
01062 }
01063 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01064
01065
01066 break;
01067 case OP_LTI:
01068 #if DEBUG_VM
01069 if(pass == 1)
01070 printf("%08x LTI\n",instruction);
01071 #endif
01072 assertInteger(opStackDepth-1);
01073 assertInteger(opStackDepth-2);
01074 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01075 opStackRegType[opStackDepth-1] = 0;
01076 opStackRegType[opStackDepth-2] = 0;
01077 opStackLoadInstructionAddr[opStackDepth-1] = 0;
01078 opStackLoadInstructionAddr[opStackDepth-2] = 0;
01079 opStackDepth -= 2;
01080 i = Constant4();
01081 jused[i] = 1;
01082 InstImm( "bc", PPC_BC, 4, 0, 8 );
01083 if ( pass==1 ) {
01084 v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01085 } else {
01086 v = 0;
01087 }
01088 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01089
01090 break;
01091 case OP_LEI:
01092 #if DEBUG_VM
01093 if(pass == 1)
01094 printf("%08x LEI\n",instruction);
01095 #endif
01096 assertInteger(opStackDepth-1);
01097 assertInteger(opStackDepth-2);
01098 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01099 opStackRegType[opStackDepth-1] = 0;
01100 opStackRegType[opStackDepth-2] = 0;
01101 opStackLoadInstructionAddr[opStackDepth-1] = 0;
01102 opStackLoadInstructionAddr[opStackDepth-2] = 0;
01103 opStackDepth -= 2;
01104 i = Constant4();
01105 jused[i] = 1;
01106 InstImm( "bc", PPC_BC, 12, 1, 8 );
01107 if ( pass==1 ) {
01108 v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01109 } else {
01110 v = 0;
01111 }
01112 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01113
01114 break;
01115 case OP_GTI:
01116 #if DEBUG_VM
01117 if(pass == 1)
01118 printf("%08x GTI\n",instruction);
01119 #endif
01120 assertInteger(opStackDepth-1);
01121 assertInteger(opStackDepth-2);
01122 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01123 opStackRegType[opStackDepth-1] = 0;
01124 opStackRegType[opStackDepth-2] = 0;
01125 opStackLoadInstructionAddr[opStackDepth-1] = 0;
01126 opStackLoadInstructionAddr[opStackDepth-2] = 0;
01127 opStackDepth -= 2;
01128 i = Constant4();
01129 jused[i] = 1;
01130 InstImm( "bc", PPC_BC, 4, 1, 8 );
01131 if ( pass==1 ) {
01132 v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01133 } else {
01134 v = 0;
01135 }
01136 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01137
01138 break;
01139 case OP_GEI:
01140 #if DEBUG_VM
01141 if(pass == 1)
01142 printf("%08x GEI\n",instruction);
01143 #endif
01144 assertInteger(opStackDepth-1);
01145 assertInteger(opStackDepth-2);
01146 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01147 opStackRegType[opStackDepth-1] = 0;
01148 opStackRegType[opStackDepth-2] = 0;
01149 opStackLoadInstructionAddr[opStackDepth-1] = 0;
01150 opStackLoadInstructionAddr[opStackDepth-2] = 0;
01151 opStackDepth -= 2;
01152 i = Constant4();
01153 jused[i] = 1;
01154 InstImm( "bc", PPC_BC, 12, 0, 8 );
01155 if ( pass==1 ) {
01156 v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01157 } else {
01158 v = 0;
01159 }
01160 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01161
01162 break;
01163 case OP_LTU:
01164 #if DEBUG_VM
01165 if(pass == 1)
01166 printf("%08x LTU\n",instruction);
01167 #endif
01168 assertInteger(opStackDepth-1);
01169 assertInteger(opStackDepth-2);
01170 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01171 opStackRegType[opStackDepth-1] = 0;
01172 opStackRegType[opStackDepth-2] = 0;
01173 opStackLoadInstructionAddr[opStackDepth-1] = 0;
01174 opStackLoadInstructionAddr[opStackDepth-2] = 0;
01175 opStackDepth -= 2;
01176 i = Constant4();
01177 jused[i] = 1;
01178 InstImm( "bc", PPC_BC, 4, 0, 8 );
01179 if ( pass==1 ) {
01180 v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01181 } else {
01182 v = 0;
01183 }
01184 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01185
01186 break;
01187 case OP_LEU:
01188 #if DEBUG_VM
01189 if(pass == 1)
01190 printf("%08x LEU\n",instruction);
01191 #endif
01192 assertInteger(opStackDepth-1);
01193 assertInteger(opStackDepth-2);
01194 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01195 opStackRegType[opStackDepth-1] = 0;
01196 opStackRegType[opStackDepth-2] = 0;
01197 opStackLoadInstructionAddr[opStackDepth-1] = 0;
01198 opStackLoadInstructionAddr[opStackDepth-2] = 0;
01199 opStackDepth -= 2;
01200 i = Constant4();
01201 jused[i] = 1;
01202 InstImm( "bc", PPC_BC, 12, 1, 8 );
01203 if ( pass==1 ) {
01204 v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01205 } else {
01206 v = 0;
01207 }
01208 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01209
01210 break;
01211 case OP_GTU:
01212 #if DEBUG_VM
01213 if(pass == 1)
01214 printf(