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

vm_interpreted.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 #include "vm_local.h"
00023 
00024 #ifdef DEBUG_VM // bk001204
00025 static char *opnames[256] = {
00026     "OP_UNDEF", 
00027 
00028     "OP_IGNORE", 
00029 
00030     "OP_BREAK",
00031 
00032     "OP_ENTER",
00033     "OP_LEAVE",
00034     "OP_CALL",
00035     "OP_PUSH",
00036     "OP_POP",
00037 
00038     "OP_CONST",
00039 
00040     "OP_LOCAL",
00041 
00042     "OP_JUMP",
00043 
00044     //-------------------
00045 
00046     "OP_EQ",
00047     "OP_NE",
00048 
00049     "OP_LTI",
00050     "OP_LEI",
00051     "OP_GTI",
00052     "OP_GEI",
00053 
00054     "OP_LTU",
00055     "OP_LEU",
00056     "OP_GTU",
00057     "OP_GEU",
00058 
00059     "OP_EQF",
00060     "OP_NEF",
00061 
00062     "OP_LTF",
00063     "OP_LEF",
00064     "OP_GTF",
00065     "OP_GEF",
00066 
00067     //-------------------
00068 
00069     "OP_LOAD1",
00070     "OP_LOAD2",
00071     "OP_LOAD4",
00072     "OP_STORE1",
00073     "OP_STORE2",
00074     "OP_STORE4",
00075     "OP_ARG",
00076 
00077     "OP_BLOCK_COPY",
00078 
00079     //-------------------
00080 
00081     "OP_SEX8",
00082     "OP_SEX16",
00083 
00084     "OP_NEGI",
00085     "OP_ADD",
00086     "OP_SUB",
00087     "OP_DIVI",
00088     "OP_DIVU",
00089     "OP_MODI",
00090     "OP_MODU",
00091     "OP_MULI",
00092     "OP_MULU",
00093 
00094     "OP_BAND",
00095     "OP_BOR",
00096     "OP_BXOR",
00097     "OP_BCOM",
00098 
00099     "OP_LSH",
00100     "OP_RSHI",
00101     "OP_RSHU",
00102 
00103     "OP_NEGF",
00104     "OP_ADDF",
00105     "OP_SUBF",
00106     "OP_DIVF",
00107     "OP_MULF",
00108 
00109     "OP_CVIF",
00110     "OP_CVFI"
00111 };
00112 #endif
00113 
00114 #if idppc
00115     #if defined(__GNUC__)
00116         static inline unsigned int loadWord(void *addr) {
00117             unsigned int word;
00118             
00119             asm("lwbrx %0,0,%1" : "=r" (word) : "r" (addr));
00120             return word;
00121         }
00122     #else
00123     #define loadWord(addr) __lwbrx(addr,0)
00124     #endif
00125 #else
00126     #define loadWord(addr) *((int *)addr)
00127 #endif
00128 
00129 char *VM_Indent( vm_t *vm ) {
00130     static char *string = "                                        ";
00131     if ( vm->callLevel > 20 ) {
00132         return string;
00133     }
00134     return string + 2 * ( 20 - vm->callLevel );
00135 }
00136 
00137 void VM_StackTrace( vm_t *vm, int programCounter, int programStack ) {
00138     int     count;
00139 
00140     count = 0;
00141     do {
00142         Com_Printf( "%s\n", VM_ValueToSymbol( vm, programCounter ) );
00143         programStack =  *(int *)&vm->dataBase[programStack+4];
00144         programCounter = *(int *)&vm->dataBase[programStack];
00145     } while ( programCounter != -1 && ++count < 32 );
00146 
00147 }
00148 
00149 
00150 /*
00151 ====================
00152 VM_PrepareInterpreter
00153 ====================
00154 */
00155 void VM_PrepareInterpreter( vm_t *vm, vmHeader_t *header ) {
00156     int     op;
00157     int     pc;
00158     byte    *code;
00159     int     instruction;
00160     int     *codeBase;
00161 
00162     vm->codeBase = Hunk_Alloc( vm->codeLength*4, h_high );          // we're now int aligned
00163 //  memcpy( vm->codeBase, (byte *)header + header->codeOffset, vm->codeLength );
00164 
00165     // we don't need to translate the instructions, but we still need
00166     // to find each instructions starting point for jumps
00167     pc = 0;
00168     instruction = 0;
00169     code = (byte *)header + header->codeOffset;
00170     codeBase = (int *)vm->codeBase;
00171 
00172     while ( instruction < header->instructionCount ) {
00173         vm->instructionPointers[ instruction ] = pc;
00174         instruction++;
00175 
00176         op = code[ pc ];
00177         codeBase[pc] = op;
00178         if ( pc > header->codeLength ) {
00179             Com_Error( ERR_FATAL, "VM_PrepareInterpreter: pc > header->codeLength" );
00180         }
00181 
00182         pc++;
00183 
00184         // these are the only opcodes that aren't a single byte
00185         switch ( op ) {
00186         case OP_ENTER:
00187         case OP_CONST:
00188         case OP_LOCAL:
00189         case OP_LEAVE:
00190         case OP_EQ:
00191         case OP_NE:
00192         case OP_LTI:
00193         case OP_LEI:
00194         case OP_GTI:
00195         case OP_GEI:
00196         case OP_LTU:
00197         case OP_LEU:
00198         case OP_GTU:
00199         case OP_GEU:
00200         case OP_EQF:
00201         case OP_NEF:
00202         case OP_LTF:
00203         case OP_LEF:
00204         case OP_GTF:
00205         case OP_GEF:
00206         case OP_BLOCK_COPY:
00207             codeBase[pc+0] = loadWord(&code[pc]);
00208             pc += 4;
00209             break;
00210         case OP_ARG:
00211             codeBase[pc+0] = code[pc];
00212             pc += 1;
00213             break;
00214         default:
00215             break;
00216         }
00217 
00218     }
00219     pc = 0;
00220     instruction = 0;
00221     code = (byte *)header + header->codeOffset;
00222     codeBase = (int *)vm->codeBase;
00223 
00224     while ( instruction < header->instructionCount ) {
00225         op = code[ pc ];
00226         instruction++;
00227         pc++;
00228         switch ( op ) {
00229         case OP_ENTER:
00230         case OP_CONST:
00231         case OP_LOCAL:
00232         case OP_LEAVE:
00233         case OP_EQ:
00234         case OP_NE:
00235         case OP_LTI:
00236         case OP_LEI:
00237         case OP_GTI:
00238         case OP_GEI:
00239         case OP_LTU:
00240         case OP_LEU:
00241         case OP_GTU:
00242         case OP_GEU:
00243         case OP_EQF:
00244         case OP_NEF:
00245         case OP_LTF:
00246         case OP_LEF:
00247         case OP_GTF:
00248         case OP_GEF:
00249         case OP_BLOCK_COPY:
00250             switch(op) {
00251                 case OP_EQ:
00252                 case OP_NE:
00253                 case OP_LTI:
00254                 case OP_LEI:
00255                 case OP_GTI:
00256                 case OP_GEI:
00257                 case OP_LTU:
00258                 case OP_LEU:
00259                 case OP_GTU:
00260                 case OP_GEU:
00261                 case OP_EQF:
00262                 case OP_NEF:
00263                 case OP_LTF:
00264                 case OP_LEF:
00265                 case OP_GTF:
00266                 case OP_GEF:
00267                 codeBase[pc] = vm->instructionPointers[codeBase[pc]];
00268                 break;
00269             default:
00270                 break;
00271             }
00272             pc += 4;
00273             break;
00274         case OP_ARG:
00275             pc += 1;
00276             break;
00277         default:
00278             break;
00279         }
00280 
00281     }
00282 }
00283 
00284 /*
00285 ==============
00286 VM_Call
00287 
00288 
00289 Upon a system call, the stack will look like:
00290 
00291 sp+32   parm1
00292 sp+28   parm0
00293 sp+24   return stack
00294 sp+20   return address
00295 sp+16   local1
00296 sp+14   local0
00297 sp+12   arg1
00298 sp+8    arg0
00299 sp+4    return stack
00300 sp      return address
00301 
00302 An interpreted function will immediately execute
00303 an OP_ENTER instruction, which will subtract space for
00304 locals from sp
00305 ==============
00306 */
00307 #define MAX_STACK   256
00308 #define STACK_MASK  (MAX_STACK-1)
00309 //#define   DEBUG_VM
00310 
00311 #define DEBUGSTR va("%s%i", VM_Indent(vm), opStack-stack )
00312 
00313 int VM_CallInterpreted( vm_t *vm, int *args ) {
00314     int     stack[MAX_STACK];
00315     int     *opStack;
00316     int     programCounter;
00317     int     programStack;
00318     int     stackOnEntry;
00319     byte    *image;
00320     int     *codeImage;
00321     int     v1;
00322     int     dataMask;
00323 #ifdef DEBUG_VM
00324     vmSymbol_t  *profileSymbol;
00325 #endif
00326 
00327     // interpret the code
00328     vm->currentlyInterpreting = qtrue;
00329 
00330     // we might be called recursively, so this might not be the very top
00331     programStack = stackOnEntry = vm->programStack;
00332 
00333 #ifdef DEBUG_VM
00334     profileSymbol = VM_ValueToFunctionSymbol( vm, 0 );
00335     // uncomment this for debugging breakpoints
00336     vm->breakFunction = 0;
00337 #endif
00338     // set up the stack frame 
00339 
00340     image = vm->dataBase;
00341     codeImage = (int *)vm->codeBase;
00342     dataMask = vm->dataMask;
00343     
00344     // leave a free spot at start of stack so
00345     // that as long as opStack is valid, opStack-1 will
00346     // not corrupt anything
00347     opStack = stack;
00348     programCounter = 0;
00349 
00350     programStack -= 48;
00351 
00352     *(int *)&image[ programStack + 44] = args[9];
00353     *(int *)&image[ programStack + 40] = args[8];
00354     *(int *)&image[ programStack + 36] = args[7];
00355     *(int *)&image[ programStack + 32] = args[6];
00356     *(int *)&image[ programStack + 28] = args[5];
00357     *(int *)&image[ programStack + 24] = args[4];
00358     *(int *)&image[ programStack + 20] = args[3];
00359     *(int *)&image[ programStack + 16] = args[2];
00360     *(int *)&image[ programStack + 12] = args[1];
00361     *(int *)&image[ programStack + 8 ] = args[0];
00362     *(int *)&image[ programStack + 4 ] = 0; // return stack
00363     *(int *)&image[ programStack ] = -1;    // will terminate the loop on return
00364 
00365     vm->callLevel = 0;
00366     
00367     VM_Debug(0);
00368 
00369 //  vm_debugLevel=2;
00370     // main interpreter loop, will exit when a LEAVE instruction
00371     // grabs the -1 program counter
00372 
00373 #define r2 codeImage[programCounter]
00374 
00375     while ( 1 ) {
00376         int     opcode, r0, r1;
00377 //      unsigned int    r2;
00378 
00379 nextInstruction:
00380         r0 = ((int *)opStack)[0];
00381         r1 = ((int *)opStack)[-1];
00382 nextInstruction2:
00383         opcode = codeImage[ programCounter++ ];
00384 #ifdef DEBUG_VM
00385         if ( (unsigned)programCounter > vm->codeLength ) {
00386             Com_Error( ERR_DROP, "VM pc out of range" );
00387         }
00388 
00389         if ( opStack < stack ) {
00390             Com_Error( ERR_DROP, "VM opStack underflow" );
00391         }
00392         if ( opStack >= stack+MAX_STACK ) {
00393             Com_Error( ERR_DROP, "VM opStack overflow" );
00394         }
00395 
00396         if ( programStack <= vm->stackBottom ) {
00397             Com_Error( ERR_DROP, "VM stack overflow" );
00398         }
00399 
00400         if ( programStack & 3 ) {
00401             Com_Error( ERR_DROP, "VM program stack misaligned" );
00402         }
00403 
00404         if ( vm_debugLevel > 1 ) {
00405             Com_Printf( "%s %s\n", DEBUGSTR, opnames[opcode] );
00406         }
00407         profileSymbol->profileCount++;
00408 #endif
00409 
00410         switch ( opcode ) {
00411 #ifdef DEBUG_VM
00412         default:
00413             Com_Error( ERR_DROP, "Bad VM instruction" );  // this should be scanned on load!
00414 #endif
00415         case OP_BREAK:
00416             vm->breakCount++;
00417             goto nextInstruction2;
00418         case OP_CONST:
00419             opStack++;
00420             r1 = r0;
00421             r0 = *opStack = r2;
00422             
00423             programCounter += 4;
00424             goto nextInstruction2;
00425         case OP_LOCAL:
00426             opStack++;
00427             r1 = r0;
00428             r0 = *opStack = r2+programStack;
00429 
00430             programCounter += 4;
00431             goto nextInstruction2;
00432 
00433         case OP_LOAD4:
00434 #ifdef DEBUG_VM
00435             if ( *opStack & 3 ) {
00436                 Com_Error( ERR_DROP, "OP_LOAD4 misaligned" );
00437             }
00438 #endif
00439             r0 = *opStack = *(int *)&image[ r0&dataMask ];
00440             goto nextInstruction2;
00441         case OP_LOAD2:
00442             r0 = *opStack = *(unsigned short *)&image[ r0&dataMask ];
00443             goto nextInstruction2;
00444         case OP_LOAD1:
00445             r0 = *opStack = image[ r0&dataMask ];
00446             goto nextInstruction2;
00447 
00448         case OP_STORE4:
00449             *(int *)&image[ r1&(dataMask & ~3) ] = r0;
00450             opStack -= 2;
00451             goto nextInstruction;
00452         case OP_STORE2:
00453             *(short *)&image[ r1&(dataMask & ~1) ] = r0;
00454             opStack -= 2;
00455             goto nextInstruction;
00456         case OP_STORE1:
00457             image[ r1&dataMask ] = r0;
00458             opStack -= 2;
00459             goto nextInstruction;
00460 
00461         case OP_ARG:
00462             // single byte offset from programStack
00463             *(int *)&image[ codeImage[programCounter] + programStack ] = r0;
00464             opStack--;
00465             programCounter += 1;
00466             goto nextInstruction;
00467 
00468         case OP_BLOCK_COPY:
00469             {
00470                 int     *src, *dest;
00471                 int     i, count, srci, desti;
00472 
00473                 count = r2;
00474                 // MrE: copy range check
00475                 srci = r0 & dataMask;
00476                 desti = r1 & dataMask;
00477                 count = ((srci + count) & dataMask) - srci;
00478                 count = ((desti + count) & dataMask) - desti;
00479 
00480                 src = (int *)&image[ r0&dataMask ];
00481                 dest = (int *)&image[ r1&dataMask ];
00482                 if ( ( (int)src | (int)dest | count ) & 3 ) {
00483                     Com_Error( ERR_DROP, "OP_BLOCK_COPY not dword aligned" );
00484                 }
00485                 count >>= 2;
00486                 for ( i = count-1 ; i>= 0 ; i-- ) {
00487                     dest[i] = src[i];
00488                 }
00489                 programCounter += 4;
00490                 opStack -= 2;
00491             }
00492             goto nextInstruction;
00493 
00494         case OP_CALL:
00495             // save current program counter
00496             *(int *)&image[ programStack ] = programCounter;
00497             
00498             // jump to the location on the stack
00499             programCounter = r0;
00500             opStack--;
00501             if ( programCounter < 0 ) {
00502                 // system call
00503                 int     r;
00504                 int     temp;
00505 #ifdef DEBUG_VM
00506                 int     stomped;
00507 
00508                 if ( vm_debugLevel ) {
00509                     Com_Printf( "%s---> systemcall(%i)\n", DEBUGSTR, -1 - programCounter );
00510                 }
00511 #endif
00512                 // save the stack to allow recursive VM entry
00513                 temp = vm->callLevel;
00514                 vm->programStack = programStack - 4;
00515 #ifdef DEBUG_VM
00516                 stomped = *(int *)&image[ programStack + 4 ];
00517 #endif
00518                 *(int *)&image[ programStack + 4 ] = -1 - programCounter;
00519 
00520 //VM_LogSyscalls( (int *)&image[ programStack + 4 ] );
00521                 r = vm->systemCall( (int *)&image[ programStack + 4 ] );
00522 
00523 #ifdef DEBUG_VM
00524                 // this is just our stack frame pointer, only needed
00525                 // for debugging
00526                 *(int *)&image[ programStack + 4 ] = stomped;
00527 #endif
00528 
00529                 // save return value
00530                 opStack++;
00531                 *opStack = r;
00532                 programCounter = *(int *)&image[ programStack ];
00533                 vm->callLevel = temp;
00534 #ifdef DEBUG_VM
00535                 if ( vm_debugLevel ) {
00536                     Com_Printf( "%s<--- %s\n", DEBUGSTR, VM_ValueToSymbol( vm, programCounter ) );
00537                 }
00538 #endif
00539             } else {
00540                 programCounter = vm->instructionPointers[ programCounter ];
00541             }
00542             goto nextInstruction;
00543 
00544         // push and pop are only needed for discarded or bad function return values
00545         case OP_PUSH:
00546             opStack++;
00547             goto nextInstruction;
00548         case OP_POP:
00549             opStack--;
00550             goto nextInstruction;
00551 
00552         case OP_ENTER:
00553 #ifdef DEBUG_VM
00554             profileSymbol = VM_ValueToFunctionSymbol( vm, programCounter );
00555 #endif
00556             // get size of stack frame
00557             v1 = r2;
00558 
00559             programCounter += 4;
00560             programStack -= v1;
00561 #ifdef DEBUG_VM
00562             // save old stack frame for debugging traces
00563             *(int *)&image[programStack+4] = programStack + v1;
00564             if ( vm_debugLevel ) {
00565                 Com_Printf( "%s---> %s\n", DEBUGSTR, VM_ValueToSymbol( vm, programCounter - 5 ) );
00566                 if ( vm->breakFunction && programCounter - 5 == vm->breakFunction ) {
00567                     // this is to allow setting breakpoints here in the debugger
00568                     vm->breakCount++;
00569 //                  vm_debugLevel = 2;
00570 //                  VM_StackTrace( vm, programCounter, programStack );
00571                 }
00572                 vm->callLevel++;
00573             }
00574 #endif
00575             goto nextInstruction;
00576         case OP_LEAVE:
00577             // remove our stack frame
00578             v1 = r2;
00579 
00580             programStack += v1;
00581 
00582             // grab the saved program counter
00583             programCounter = *(int *)&image[ programStack ];
00584 #ifdef DEBUG_VM
00585             profileSymbol = VM_ValueToFunctionSymbol( vm, programCounter );
00586             if ( vm_debugLevel ) {
00587                 vm->callLevel--;
00588                 Com_Printf( "%s<--- %s\n", DEBUGSTR, VM_ValueToSymbol( vm, programCounter ) );
00589             }
00590 #endif
00591             // check for leaving the VM
00592             if ( programCounter == -1 ) {
00593                 goto done;
00594             }
00595             goto nextInstruction;
00596 
00597         /*
00598         ===================================================================
00599         BRANCHES
00600         ===================================================================
00601         */
00602 
00603         case OP_JUMP:
00604             programCounter = r0;
00605             programCounter = vm->instructionPointers[ programCounter ];
00606             opStack--;
00607             goto nextInstruction;
00608 
00609         case OP_EQ:
00610             opStack -= 2;
00611             if ( r1 == r0 ) {
00612                 programCounter = r2;    //vm->instructionPointers[r2];
00613                 goto nextInstruction;
00614             } else {
00615                 programCounter += 4;
00616                 goto nextInstruction;
00617             }
00618 
00619         case OP_NE:
00620             opStack -= 2;
00621             if ( r1 != r0 ) {
00622                 programCounter = r2;    //vm->instructionPointers[r2];
00623                 goto nextInstruction;
00624             } else {
00625                 programCounter += 4;
00626                 goto nextInstruction;
00627             }
00628 
00629         case OP_LTI:
00630             opStack -= 2;
00631             if ( r1 < r0 ) {
00632                 programCounter = r2;    //vm->instructionPointers[r2];
00633                 goto nextInstruction;
00634             } else {
00635                 programCounter += 4;
00636                 goto nextInstruction;
00637             }
00638 
00639         case OP_LEI:
00640             opStack -= 2;
00641             if ( r1 <= r0 ) {
00642                 programCounter = r2;    //vm->instructionPointers[r2];
00643                 goto nextInstruction;
00644             } else {
00645                 programCounter += 4;
00646                 goto nextInstruction;
00647             }
00648 
00649         case OP_GTI:
00650             opStack -= 2;
00651             if ( r1 > r0 ) {
00652                 programCounter = r2;    //vm->instructionPointers[r2];
00653                 goto nextInstruction;
00654             } else {
00655                 programCounter += 4;
00656                 goto nextInstruction;
00657             }
00658 
00659         case OP_GEI:
00660             opStack -= 2;
00661             if ( r1 >= r0 ) {
00662                 programCounter = r2;    //vm->instructionPointers[r2];
00663                 goto nextInstruction;
00664             } else {
00665                 programCounter += 4;
00666                 goto nextInstruction;
00667             }
00668 
00669         case OP_LTU:
00670             opStack -= 2;
00671             if ( ((unsigned)r1) < ((unsigned)r0) ) {
00672                 programCounter = r2;    //vm->instructionPointers[r2];
00673                 goto nextInstruction;
00674             } else {
00675                 programCounter += 4;
00676                 goto nextInstruction;
00677             }
00678 
00679         case OP_LEU:
00680             opStack -= 2;
00681             if ( ((unsigned)r1) <= ((unsigned)r0) ) {
00682                 programCounter = r2;    //vm->instructionPointers[r2];
00683                 goto nextInstruction;
00684             } else {
00685                 programCounter += 4;
00686                 goto nextInstruction;
00687             }
00688 
00689         case OP_GTU:
00690             opStack -= 2;
00691             if ( ((unsigned)r1) > ((unsigned)r0) ) {
00692                 programCounter = r2;    //vm->instructionPointers[r2];
00693                 goto nextInstruction;
00694             } else {
00695                 programCounter += 4;
00696                 goto nextInstruction;
00697             }
00698 
00699         case OP_GEU:
00700             opStack -= 2;
00701             if ( ((unsigned)r1) >= ((unsigned)r0) ) {
00702                 programCounter = r2;    //vm->instructionPointers[r2];
00703                 goto nextInstruction;
00704             } else {
00705                 programCounter += 4;
00706                 goto nextInstruction;
00707             }
00708 
00709         case OP_EQF:
00710             if ( ((float *)opStack)[-1] == *(float *)opStack ) {
00711                 programCounter = r2;    //vm->instructionPointers[r2];
00712                 opStack -= 2;
00713                 goto nextInstruction;
00714             } else {
00715                 programCounter += 4;
00716                 opStack -= 2;
00717                 goto nextInstruction;
00718             }
00719 
00720         case OP_NEF:
00721             if ( ((float *)opStack)[-1] != *(float *)opStack ) {
00722                 programCounter = r2;    //vm->instructionPointers[r2];
00723                 opStack -= 2;
00724                 goto nextInstruction;
00725             } else {
00726                 programCounter += 4;
00727                 opStack -= 2;
00728                 goto nextInstruction;
00729             }
00730 
00731         case OP_LTF:
00732             if ( ((float *)opStack)[-1] < *(float *)opStack ) {
00733                 programCounter = r2;    //vm->instructionPointers[r2];
00734                 opStack -= 2;
00735                 goto nextInstruction;
00736             } else {
00737                 programCounter += 4;
00738                 opStack -= 2;
00739                 goto nextInstruction;
00740             }
00741 
00742         case OP_LEF:
00743             if ( ((float *)opStack)[-1] <= *(float *)opStack ) {
00744                 programCounter = r2;    //vm->instructionPointers[r2];
00745                 opStack -= 2;
00746                 goto nextInstruction;
00747             } else {
00748                 programCounter += 4;
00749                 opStack -= 2;
00750                 goto nextInstruction;
00751             }
00752 
00753         case OP_GTF:
00754             if ( ((float *)opStack)[-1] > *(float *)opStack ) {
00755                 programCounter = r2;    //vm->instructionPointers[r2];
00756                 opStack -= 2;
00757                 goto nextInstruction;
00758             } else {
00759                 programCounter += 4;
00760                 opStack -= 2;
00761                 goto nextInstruction;
00762             }
00763 
00764         case OP_GEF:
00765             if ( ((float *)opStack)[-1] >= *(float *)opStack ) {
00766                 programCounter = r2;    //vm->instructionPointers[r2];
00767                 opStack -= 2;
00768                 goto nextInstruction;
00769             } else {
00770                 programCounter += 4;
00771                 opStack -= 2;
00772                 goto nextInstruction;
00773             }
00774 
00775 
00776         //===================================================================
00777 
00778         case OP_NEGI:
00779             *opStack = -r0;
00780             goto nextInstruction;
00781         case OP_ADD:
00782             opStack[-1] = r1 + r0;
00783             opStack--;
00784             goto nextInstruction;
00785         case OP_SUB:
00786             opStack[-1] = r1 - r0;
00787             opStack--;
00788             goto nextInstruction;
00789         case OP_DIVI:
00790             opStack[-1] = r1 / r0;
00791             opStack--;
00792             goto nextInstruction;
00793         case OP_DIVU:
00794             opStack[-1] = ((unsigned)r1) / ((unsigned)r0);
00795             opStack--;
00796             goto nextInstruction;
00797         case OP_MODI:
00798             opStack[-1] = r1 % r0;
00799             opStack--;
00800             goto nextInstruction;
00801         case OP_MODU:
00802             opStack[-1] = ((unsigned)r1) % (unsigned)r0;
00803             opStack--;
00804             goto nextInstruction;
00805         case OP_MULI:
00806             opStack[-1] = r1 * r0;
00807             opStack--;
00808             goto nextInstruction;
00809         case OP_MULU:
00810             opStack[-1] = ((unsigned)r1) * ((unsigned)r0);
00811             opStack--;
00812             goto nextInstruction;
00813 
00814         case OP_BAND:
00815             opStack[-1] = ((unsigned)r1) & ((unsigned)r0);
00816             opStack--;
00817             goto nextInstruction;
00818         case OP_BOR:
00819             opStack[-1] = ((unsigned)r1) | ((unsigned)r0);
00820             opStack--;
00821             goto nextInstruction;
00822         case OP_BXOR:
00823             opStack[-1] = ((unsigned)r1) ^ ((unsigned)r0);
00824             opStack--;
00825             goto nextInstruction;
00826         case OP_BCOM:
00827             opStack[-1] = ~ ((unsigned)r0);
00828             goto nextInstruction;
00829 
00830         case OP_LSH:
00831             opStack[-1] = r1 << r0;
00832             opStack--;
00833             goto nextInstruction;
00834         case OP_RSHI:
00835             opStack[-1] = r1 >> r0;
00836             opStack--;
00837             goto nextInstruction;
00838         case OP_RSHU:
00839             opStack[-1] = ((unsigned)r1) >> r0;
00840             opStack--;
00841             goto nextInstruction;
00842 
00843         case OP_NEGF:
00844             *(float *)opStack =  -*(float *)opStack;
00845             goto nextInstruction;
00846         case OP_ADDF:
00847             *(float *)(opStack-1) = *(float *)(opStack-1) + *(float *)opStack;
00848             opStack--;
00849             goto nextInstruction;
00850         case OP_SUBF:
00851             *(float *)(opStack-1) = *(float *)(opStack-1) - *(float *)opStack;
00852             opStack--;
00853             goto nextInstruction;
00854         case OP_DIVF:
00855             *(float *)(opStack-1) = *(float *)(opStack-1) / *(float *)opStack;
00856             opStack--;
00857             goto nextInstruction;
00858         case OP_MULF:
00859             *(float *)(opStack-1) = *(float *)(opStack-1) * *(float *)opStack;
00860             opStack--;
00861             goto nextInstruction;
00862 
00863         case OP_CVIF:
00864             *(float *)opStack =  (float)*opStack;
00865             goto nextInstruction;
00866         case OP_CVFI:
00867             *opStack = (int) *(float *)opStack;
00868             goto nextInstruction;
00869         case OP_SEX8:
00870             *opStack = (signed char)*opStack;
00871             goto nextInstruction;
00872         case OP_SEX16:
00873             *opStack = (short)*opStack;
00874             goto nextInstruction;
00875         }
00876     }
00877 
00878 done:
00879     vm->currentlyInterpreting = qfalse;
00880 
00881     if ( opStack != &stack[1] ) {
00882         Com_Error( ERR_DROP, "Interpreter error: opStack = %i", opStack - stack );
00883     }
00884 
00885     vm->programStack = stackOnEntry;
00886 
00887     // return the result
00888     return *opStack;
00889 }

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