diff options
Diffstat (limited to 'src/qcommon')
-rw-r--r-- | src/qcommon/vm_interpreted.c | 8 | ||||
-rw-r--r-- | src/qcommon/vm_ppc.c | 1448 | ||||
-rw-r--r-- | src/qcommon/vm_ppc_new.c | 2072 | ||||
-rw-r--r-- | src/qcommon/vm_x86_64.c | 96 |
4 files changed, 1083 insertions, 2541 deletions
diff --git a/src/qcommon/vm_interpreted.c b/src/qcommon/vm_interpreted.c index 00aa4710..35096e5b 100644 --- a/src/qcommon/vm_interpreted.c +++ b/src/qcommon/vm_interpreted.c @@ -395,9 +395,8 @@ nextInstruction: r0 = ((int *)opStack)[0]; r1 = ((int *)opStack)[-1]; nextInstruction2: - opcode = codeImage[ programCounter++ ]; #ifdef DEBUG_VM - if ( (unsigned)programCounter > vm->codeLength ) { + if ( (unsigned)programCounter >= vm->codeLength ) { Com_Error( ERR_DROP, "VM pc out of range" ); } @@ -421,6 +420,7 @@ nextInstruction2: } profileSymbol->profileCount++; #endif + opcode = codeImage[ programCounter++ ]; switch ( opcode ) { #ifdef DEBUG_VM @@ -565,6 +565,8 @@ nextInstruction2: Com_Printf( "%s<--- %s\n", DEBUGSTR, VM_ValueToSymbol( vm, programCounter ) ); } #endif + } else if ( (unsigned)programCounter >= vm->codeLength ) { + Com_Error( ERR_DROP, "VM program counter out of range in OP_CALL" ); } else { programCounter = vm->instructionPointers[ programCounter ]; } @@ -620,6 +622,8 @@ nextInstruction2: // check for leaving the VM if ( programCounter == -1 ) { goto done; + } else if ( (unsigned)programCounter >= vm->codeLength ) { + Com_Error( ERR_DROP, "VM program counter out of range in OP_LEAVE" ); } goto nextInstruction; diff --git a/src/qcommon/vm_ppc.c b/src/qcommon/vm_ppc.c index 9475a833..79fc506f 100644 --- a/src/qcommon/vm_ppc.c +++ b/src/qcommon/vm_ppc.c @@ -25,8 +25,101 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "vm_local.h" -#pragma opt_pointer_analysis off +#ifdef MACOS_X +#include <CoreServices/CoreServices.h> +#endif + +#define DEBUG_VM 0 + +#if DEBUG_VM +static char *opnames[256] = { + "OP_UNDEF", + + "OP_IGNORE", + + "OP_BREAK", + + "OP_ENTER", + "OP_LEAVE", + "OP_CALL", + "OP_PUSH", + "OP_POP", + + "OP_CONST", + + "OP_LOCAL", + + "OP_JUMP", + + //------------------- + + "OP_EQ", + "OP_NE", + + "OP_LTI", + "OP_LEI", + "OP_GTI", + "OP_GEI", + + "OP_LTU", + "OP_LEU", + "OP_GTU", + "OP_GEU", + + "OP_EQF", + "OP_NEF", + + "OP_LTF", + "OP_LEF", + "OP_GTF", + "OP_GEF", + + //------------------- + + "OP_LOAD1", + "OP_LOAD2", + "OP_LOAD4", + "OP_STORE1", + "OP_STORE2", + "OP_STORE4", + "OP_ARG", + "OP_BLOCK_COPY", + + //------------------- + + "OP_SEX8", + "OP_SEX16", + + "OP_NEGI", + "OP_ADD", + "OP_SUB", + "OP_DIVI", + "OP_DIVU", + "OP_MODI", + "OP_MODU", + "OP_MULI", + "OP_MULU", + + "OP_BAND", + "OP_BOR", + "OP_BXOR", + "OP_BCOM", + + "OP_LSH", + "OP_RSHI", + "OP_RSHU", + + "OP_NEGF", + "OP_ADDF", + "OP_SUBF", + "OP_DIVF", + "OP_MULF", + + "OP_CVIF", + "OP_CVFI" +}; +#endif typedef enum { R_REAL_STACK = 1, @@ -64,6 +157,42 @@ typedef enum { #define RG_SECOND r13 #define RG_EA r14 +// The deepest value I saw in the Quake3 games was 9. +#define OP_STACK_MAX_DEPTH 16 + +// These are all volatile and thus must be saved upon entry to the VM code. +// NOTE: These are General Purpose Registers (GPR) numbers like the +// R_ definitions in the regNums_t enum above (31 is the max) +static int opStackIntRegisters[OP_STACK_MAX_DEPTH] = +{ + 16, 17, 18, 19, + 20, 21, 22, 23, + 24, 25, 26, 27, + 28, 29, 30, 31 +}; + +static unsigned int *opStackLoadInstructionAddr[OP_STACK_MAX_DEPTH]; + +// We use different registers for the floating point +// operand stack (these are volatile in the PPC ABI) +// NOTE: these are Floating Point Register (FPR) numbers, not +// General Purpose Register (GPR) numbers +static int opStackFloatRegisters[OP_STACK_MAX_DEPTH] = +{ + 0, 1, 2, 3, + 4, 5, 6, 7, + 8, 9, 10, 11, + 12, 13, 14, 15 +}; + +static int opStackRegType[OP_STACK_MAX_DEPTH] = +{ + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 +}; + // this doesn't have the low order bits set for instructions i'm not using... typedef enum { PPC_TDI = 0x08000000, @@ -200,7 +329,7 @@ typedef enum { PPC_MCRXR = 0x7c000000, PPC_LSWX = 0x7c000000, PPC_LWBRX = 0x7c000000, - PPC_LFSX = 0x7c000000, + PPC_LFSX = 0x7c00042e, PPC_SRW = 0x7c000430, PPC_SRD = 0x7c000000, PPC_TLBSYNC = 0x7c000000, @@ -213,7 +342,7 @@ typedef enum { PPC_MFSRIN = 0x7c000000, PPC_STSWX = 0x7c000000, PPC_STWBRX = 0x7c000000, - PPC_STFSX = 0x7c000000, + PPC_STFSX = 0x7c00052e, PPC_STFSUX = 0x7c000000, PPC_STSWI = 0x7c000000, PPC_STFDX = 0x7c000000, @@ -309,6 +438,7 @@ typedef enum { // the newly generated code static unsigned *buf; static int compiledOfs; // in dwords +static int pass; // fromt the original bytecode static byte *code; @@ -334,83 +464,179 @@ static int Constant1( void ) { return v; } -static void Emit4( int i ) { +static void Emit4( char *opname, int i ) { + #if DEBUG_VM + if(pass == 1) + printf("\t\t\t%p %s\t%08lx\n",&buf[compiledOfs],opname,i&0x3ffffff); + #endif buf[ compiledOfs ] = i; compiledOfs++; } -static void Inst( int opcode, int destReg, int aReg, int bReg ) { +static void Inst( char *opname, int opcode, int destReg, int aReg, int bReg ) { unsigned r; + #if DEBUG_VM + if(pass == 1) + printf("\t\t\t%p %s\tr%d,r%d,r%d\n",&buf[compiledOfs],opname,destReg,aReg,bReg); + #endif r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) ; buf[ compiledOfs ] = r; compiledOfs++; } -static void Inst4( int opcode, int destReg, int aReg, int bReg, int cReg ) { +static void Inst4( char *opname, int opcode, int destReg, int aReg, int bReg, int cReg ) { unsigned r; + #if DEBUG_VM + if(pass == 1) + printf("\t\t\t%p %s\tr%d,r%d,r%d,r%d\n",&buf[compiledOfs],opname,destReg,aReg,bReg,cReg); + #endif r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) | ( cReg << 6 ); buf[ compiledOfs ] = r; compiledOfs++; } -static void InstImm( int opcode, int destReg, int aReg, int immediate ) { +static void InstImm( char *opname, int opcode, int destReg, int aReg, int immediate ) { unsigned r; if ( immediate > 32767 || immediate < -32768 ) { Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range, opcode %x,%d,%d", immediate, opcode, destReg, aReg ); } + #if DEBUG_VM + if(pass == 1) + printf("\t\t\t%p %s\tr%d,r%d,0x%x\n",&buf[compiledOfs],opname,destReg,aReg,immediate); + #endif r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff ); buf[ compiledOfs ] = r; compiledOfs++; } -static void InstImmU( int opcode, int destReg, int aReg, int immediate ) { +static void InstImmU( char *opname, int opcode, int destReg, int aReg, int immediate ) { unsigned r; if ( immediate > 0xffff || immediate < 0 ) { Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range", immediate ); } + #if DEBUG_VM + if(pass == 1) + printf("\t\t\t%p %s\tr%d,r%d,0x%x\n",&buf[compiledOfs],opname,destReg,aReg,immediate); + #endif r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff ); buf[ compiledOfs ] = r; compiledOfs++; } -static qboolean rtopped; static int pop0, pop1, oc0, oc1; static vm_t *tvm; static int instruction; static byte *jused; -static int pass; -static void ltop() { - if (rtopped == qfalse) { - InstImm( PPC_LWZ, R_TOP, R_OPSTACK, 0 ); // get value from opstack - } +static void spillOpStack(int depth) +{ + // Store out each register on the operand stack to it's correct location. + int i; + + for(i = 0; i < depth; i++) + { + assert(opStackRegType[i]); + assert(opStackRegType[i] == 1); + switch(opStackRegType[i]) + { + case 1: // Integer register + InstImm( "stw", PPC_STW, opStackIntRegisters[i], R_OPSTACK, i*4+4); + break; + case 2: // Float register + InstImm( "stfs", PPC_STFS, opStackFloatRegisters[i], R_OPSTACK, i*4+4); + break; + } + opStackRegType[i] = 0; + } } -static void ltopandsecond() { - if (pass>=0 && buf[compiledOfs-1] == (PPC_STWU | R_TOP<<21 | R_OPSTACK<<16 | 4 ) && jused[instruction]==0 ) { - compiledOfs--; - if (!pass) { - tvm->instructionPointers[instruction] = compiledOfs * 4; - } - InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack - InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 ); - } else if (pass>=0 && buf[compiledOfs-1] == (PPC_STW | R_TOP<<21 | R_OPSTACK<<16 | 0 ) && jused[instruction]==0 ) { - compiledOfs--; - if (!pass) { - tvm->instructionPointers[instruction] = compiledOfs * 4; +static void loadOpStack(int depth) +{ + // Back off operand stack pointer and reload all operands. +// InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, -(depth)*4 ); + + int i; + + for(i = 0; i < depth; i++) + { + assert(opStackRegType[i] == 0); + // For now we're stuck reloading everything as an integer. + opStackLoadInstructionAddr[i] = &buf[compiledOfs]; + InstImm( "lwz", PPC_LWZ, opStackIntRegisters[i], R_OPSTACK, i*4+4); + opStackRegType[i] = 1; + } +} + +static void makeFloat(int depth) +{ + //assert(opStackRegType[depth] == 1); + if(opStackRegType[depth] == 1) + { + unsigned instruction; + unsigned destReg, aReg, bReg, imm; + + if(opStackLoadInstructionAddr[depth]) + { + // Repatch load instruction to use LFS instead of LWZ + instruction = *opStackLoadInstructionAddr[depth]; + // Figure out if it's LWZ or LWZX + if((instruction & 0xfc000000) == PPC_LWZ) + { + //printf("patching LWZ at %p to LFS at depth %ld\n",opStackLoadInstructionAddr[depth],depth); + //printf("old instruction: %08lx\n",instruction); + // Extract registers + destReg = (instruction >> 21) & 31; + aReg = (instruction >> 16) & 31; + imm = instruction & 0xffff; + + // Calculate correct FP register to use. + // THIS ASSUMES REGISTER USAGE FOR THE STACK IS n, n+1, n+2, etc! + //printf("old dest: %ld\n",destReg); + destReg = (destReg - opStackIntRegisters[0]) + opStackFloatRegisters[0]; + instruction = PPC_LFS | ( destReg << 21 ) | ( aReg << 16 ) | imm ; + //printf("new dest: %ld\n",destReg); + //printf("new instruction: %08lx\n",instruction); + } + else + { + //printf("patching LWZX at %p to LFSX at depth %ld\n",opStackLoadInstructionAddr[depth],depth); + //printf("old instruction: %08lx\n",instruction); + // Extract registers + destReg = (instruction >> 21) & 31; + aReg = (instruction >> 16) & 31; + bReg = (instruction >> 11) & 31; + // Calculate correct FP register to use. + // THIS ASSUMES REGISTER USAGE FOR THE STACK IS n, n+1, n+2, etc! + //printf("old dest: %ld\n",destReg); + destReg = (destReg - opStackIntRegisters[0]) + opStackFloatRegisters[0]; + instruction = PPC_LFSX | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) ; + //printf("new dest: %ld\n",destReg); + //printf("new instruction: %08lx\n",instruction); + } + *opStackLoadInstructionAddr[depth] = instruction; + opStackLoadInstructionAddr[depth] = 0; + } + else + { + //printf("doing float constant load at %p for depth %ld\n",&buf[compiledOfs],depth); + // It was likely loaded as a constant so we have to save/load it. A more + // interesting implementation might be to generate code to do a "PC relative" + // load from the VM code region. + InstImm( "stw", PPC_STW, opStackIntRegisters[depth], R_OPSTACK, depth*4+4); + // For XXX make sure we force enough NOPs to get the load into + // another dispatch group to avoid pipeline flush. + Inst( "ori", PPC_ORI, 0, 0, 0 ); + Inst( "ori", PPC_ORI, 0, 0, 0 ); + Inst( "ori", PPC_ORI, 0, 0, 0 ); + Inst( "ori", PPC_ORI, 0, 0, 0 ); + InstImm( "lfs", PPC_LFS, opStackFloatRegisters[depth], R_OPSTACK, depth*4+4); + } + opStackRegType[depth] = 2; } - InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, -4 ); // get value from opstack - InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 ); - } else { - ltop(); // get value from opstack - InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, -4 ); // get value from opstack - InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 ); - } - rtopped = qfalse; } // TJW: Unused @@ -422,6 +648,7 @@ static void fltop() { } #endif +#if 0 static void fltopandsecond() { InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack InstImm( PPC_LFS, R_SECOND, R_OPSTACK, -4 ); // get value from opstack @@ -429,6 +656,9 @@ static void fltopandsecond() { rtopped = qfalse; return; } +#endif + +#define assertInteger(depth) assert(opStackRegType[depth] == 1) /* ================= @@ -440,7 +670,10 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { int maxLength; int v; int i; - + int opStackDepth; + + int mainFunction; + // set up the into-to-float variables ((int *)itofConvert)[0] = 0x43300000; ((int *)itofConvert)[1] = 0x80000000; @@ -456,9 +689,10 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { // pointers for branches for ( pass = -1 ; pass < 2 ; pass++ ) { - rtopped = qfalse; // translate all instructions pc = 0; + mainFunction = 0; + opStackDepth = 0; pop0 = 343545; pop1 = 2443545; @@ -473,7 +707,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { Emit4( 0 ); #endif - for ( instruction = 0 ; instruction < header->instructionCount ; instruction++ ) { + for ( instruction = 0 ; instruction < header->instructionCount ; instruction++ ) { if ( compiledOfs*4 > maxLength - 16 ) { Com_Error( ERR_DROP, "VM_Compile: maxLength exceeded" ); } @@ -487,651 +721,988 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { case 0: break; case OP_BREAK: - InstImmU( PPC_ADDI, R_TOP, 0, 0 ); - InstImm( PPC_LWZ, R_TOP, R_TOP, 0 ); // *(int *)0 to crash to debugger - rtopped = qfalse; + #if DEBUG_VM + if(pass == 1) + printf("%08lx BREAK\n",instruction); + #endif + InstImmU( "addi", PPC_ADDI, R_TOP, 0, 0 ); + InstImm( "lwz", PPC_LWZ, R_TOP, R_TOP, 0 ); // *(int *)0 to crash to debugger break; case OP_ENTER: - InstImm( PPC_ADDI, R_STACK, R_STACK, -Constant4() ); // sub R_STACK, R_STACK, imm - rtopped = qfalse; + opStackDepth = 0; + v = Constant4(); + #if DEBUG_VM + if(pass == 1) + printf("%08x ENTER\t%04x\n",instruction,v); + #endif + opStackRegType[opStackDepth] = 0; + mainFunction++; + if(mainFunction == 1) + { + // Main VM entry point is the first thing we compile, so save off operand stack + // registers here. This avoids issues with trying to trick the native compiler + // into doing it, and properly matches the PowerPC ABI + InstImm( "addi", PPC_ADDI, R_REAL_STACK, R_REAL_STACK, -OP_STACK_MAX_DEPTH*4 ); // sub R_STACK, R_STACK, imm + for(i = 0; i < OP_STACK_MAX_DEPTH; i++) + InstImm( "stw", PPC_STW, opStackIntRegisters[i], R_REAL_STACK, i*4); + } + InstImm( "addi", PPC_ADDI, R_STACK, R_STACK, -v ); // sub R_STACK, R_STACK, imm break; case OP_CONST: v = Constant4(); - if (code[pc] == OP_LOAD4 || code[pc] == OP_LOAD2 || code[pc] == OP_LOAD1) { - v &= vm->dataMask; - } + #if DEBUG_VM + if(pass == 1) + printf("%08x CONST\t%08x\n",instruction,v); + #endif + opStackLoadInstructionAddr[opStackDepth] = 0; if ( v < 32768 && v >= -32768 ) { - InstImmU( PPC_ADDI, R_TOP, 0, v & 0xffff ); + InstImmU( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth], 0, v & 0xffff ); } else { - InstImmU( PPC_ADDIS, R_TOP, 0, (v >> 16)&0xffff ); + InstImmU( "addis", PPC_ADDIS, opStackIntRegisters[opStackDepth], 0, (v >> 16)&0xffff ); if ( v & 0xffff ) { - InstImmU( PPC_ORI, R_TOP, R_TOP, v & 0xffff ); + InstImmU( "ori", PPC_ORI, opStackIntRegisters[opStackDepth], opStackIntRegisters[opStackDepth], v & 0xffff ); } } - if (code[pc] == OP_LOAD4) { - Inst( PPC_LWZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base - pc++; - instruction++; - } else if (code[pc] == OP_LOAD2) { - Inst( PPC_LHZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base - pc++; - instruction++; - } else if (code[pc] == OP_LOAD1) { - Inst( PPC_LBZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base - pc++; - instruction++; - } - if (code[pc] == OP_STORE4) { - InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack - InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 ); - //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it - Inst( PPC_STWX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base - pc++; - instruction++; - rtopped = qfalse; - break; - } else if (code[pc] == OP_STORE2) { - InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack - InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 ); - //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it - Inst( PPC_STHX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base - pc++; - instruction++; - rtopped = qfalse; - break; - } else if (code[pc] == OP_STORE1) { - InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack - InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 ); - //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it - Inst( PPC_STBX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base - pc++; - instruction++; - rtopped = qfalse; - break; - } + opStackRegType[opStackDepth] = 1; + opStackDepth += 1; if (code[pc] == OP_JUMP) { jused[v] = 1; } - InstImm( PPC_STWU, R_TOP, R_OPSTACK, 4 ); - rtopped = qtrue; break; case OP_LOCAL: - oc0 = oc1; oc1 = Constant4(); + #if DEBUG_VM + if(pass == 1) + printf("%08x LOCAL\t%08x\n",instruction,oc1); + #endif if (code[pc] == OP_LOAD4 || code[pc] == OP_LOAD2 || code[pc] == OP_LOAD1) { oc1 &= vm->dataMask; } - InstImm( PPC_ADDI, R_TOP, R_STACK, oc1 ); - if (code[pc] == OP_LOAD4) { - Inst( PPC_LWZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base - pc++; - instruction++; - } else if (code[pc] == OP_LOAD2) { - Inst( PPC_LHZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base - pc++; - instruction++; - } else if (code[pc] == OP_LOAD1) { - Inst( PPC_LBZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base - pc++; - instruction++; - } - if (code[pc] == OP_STORE4) { - InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack - InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 ); - //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it - Inst( PPC_STWX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base - pc++; - instruction++; - rtopped = qfalse; - break; - } else if (code[pc] == OP_STORE2) { - InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack - InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 ); - //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it - Inst( PPC_STHX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base - pc++; - instruction++; - rtopped = qfalse; - break; - } else if (code[pc] == OP_STORE1) { - InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack - InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 ); - //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it - Inst( PPC_STBX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base - pc++; - instruction++; - rtopped = qfalse; - break; - } - InstImm( PPC_STWU, R_TOP, R_OPSTACK, 4 ); - rtopped = qtrue; + InstImm( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth], R_STACK, oc1 ); + opStackRegType[opStackDepth] = 1; + opStackLoadInstructionAddr[opStackDepth] = 0; + opStackDepth += 1; break; case OP_ARG: - ltop(); // get value from opstack - InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 ); - InstImm( PPC_ADDI, R_EA, R_STACK, Constant1() ); // location to put it - Inst( PPC_STWX, R_TOP, R_EA, R_MEMBASE ); - rtopped = qfalse; + v = Constant1(); + #if DEBUG_VM + if(pass == 1) + printf("%08x ARG \t%08x\n",instruction,v); + #endif + InstImm( "addi", PPC_ADDI, R_EA, R_STACK, v ); // location to put it + if(opStackRegType[opStackDepth-1] == 1) + Inst( "stwx", PPC_STWX, opStackIntRegisters[opStackDepth-1], R_EA, R_MEMBASE ); + else + Inst( "stfsx", PPC_STFSX, opStackFloatRegisters[opStackDepth-1], R_EA, R_MEMBASE ); + opStackRegType[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackDepth -= 1; + break; case OP_CALL: - Inst( PPC_MFSPR, R_SECOND, 8, 0 ); // move from link register - InstImm( PPC_STWU, R_SECOND, R_REAL_STACK, -16 ); // save off the old return address - - Inst( PPC_MTSPR, R_ASMCALL, 9, 0 ); // move to count register - Inst( PPC_BCCTR | 1, 20, 0, 0 ); // jump and link to the count register - - InstImm( PPC_LWZ, R_SECOND, R_REAL_STACK, 0 ); // fetch the old return address - InstImm( PPC_ADDI, R_REAL_STACK, R_REAL_STACK, 16 ); - Inst( PPC_MTSPR, R_SECOND, 8, 0 ); // move to link register - rtopped = qfalse; + #if DEBUG_VM + if(pass == 1) + printf("%08x CALL\n",instruction); + #endif + assertInteger(opStackDepth-1); + assert(opStackDepth > 0); + Inst( "mflr", PPC_MFSPR, R_SECOND, 8, 0 ); // move from link register + InstImm( "stwu", PPC_STWU, R_SECOND, R_REAL_STACK, -16 ); // save off the old return address + + // Spill operand stack registers. + spillOpStack(opStackDepth); + + // We need to leave R_OPSTACK pointing to the top entry on the stack, which is the call address. + // It will be consumed (and R4 decremented) by the AsmCall code. + InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, opStackDepth*4); + + Inst( "mtctr", PPC_MTSPR, R_ASMCALL, 9, 0 ); // move to count register + Inst( "bctrl", PPC_BCCTR | 1, 20, 0, 0 ); // jump and link to the count register + + // R4 now points to the top of the operand stack, which has the return value in it. We want to + // back off the pointer to point to the base of our local operand stack and then reload the stack. + + InstImm("addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, -opStackDepth*4); + + // Reload operand stack. + loadOpStack(opStackDepth); + + InstImm( "lwz", PPC_LWZ, R_SECOND, R_REAL_STACK, 0 ); // fetch the old return address + InstImm( "addi", PPC_ADDI, R_REAL_STACK, R_REAL_STACK, 16 ); + Inst( "mtlr", PPC_MTSPR, R_SECOND, 8, 0 ); // move to link register break; case OP_PUSH: - InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, 4 ); - rtopped = qfalse; + #if DEBUG_VM + if(pass == 1) + printf("%08x PUSH\n",instruction); + #endif + opStackRegType[opStackDepth] = 1; // Garbage int value. + opStackDepth += 1; break; case OP_POP: - InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 ); - rtopped = qfalse; + #if DEBUG_VM + if(pass == 1) + printf("%08x POP\n",instruction); + #endif + opStackDepth -= 1; + opStackRegType[opStackDepth] = 0; // ?? + opStackLoadInstructionAddr[opStackDepth-1] = 0; break; case OP_LEAVE: - InstImm( PPC_ADDI, R_STACK, R_STACK, Constant4() ); // add R_STACK, R_STACK, imm - Inst( PPC_BCLR, 20, 0, 0 ); // branch unconditionally to link register - rtopped = qfalse; + #if DEBUG_VM + if(pass == 1) + printf("%08x LEAVE\n",instruction); + #endif + assert(opStackDepth == 1); + assert(opStackRegType[0] != 0); + // Save return value onto top of op stack. We also have to increment R_OPSTACK + switch(opStackRegType[0]) + { + case 1: // Integer register + InstImm( "stw", PPC_STWU, opStackIntRegisters[0], R_OPSTACK, 4); + break; + case 2: // Float register + InstImm( "stfs", PPC_STFSU, opStackFloatRegisters[0], R_OPSTACK, 4); + break; + } + InstImm( "addi", PPC_ADDI, R_STACK, R_STACK, Constant4() ); // add R_STACK, R_STACK, imm + if(mainFunction == 1) + { + for(i = 0; i < OP_STACK_MAX_DEPTH; i++) + InstImm( "lwz", PPC_LWZ, opStackIntRegisters[i], R_REAL_STACK, i*4); + InstImm( "addi", PPC_ADDI, R_REAL_STACK, R_REAL_STACK, OP_STACK_MAX_DEPTH*4 ); + } + opStackDepth--; + opStackRegType[opStackDepth] = 0; + opStackLoadInstructionAddr[opStackDepth] = 0; + Inst( "blr", PPC_BCLR, 20, 0, 0 ); // branch unconditionally to link register break; case OP_LOAD4: - ltop(); // get value from opstack - //Inst( PPC_AND, R_MEMMASK, R_TOP, R_TOP ); // mask it - Inst( PPC_LWZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base - InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); - rtopped = qtrue; + #if DEBUG_VM + if(pass == 1) + printf("%08x LOAD4\n",instruction); + #endif + // We should try to figure out whether to use LWZX or LFSX based + // on some kind of code analysis after subsequent passes. I think what + // we could do is store the compiled load instruction address along with + // the register type. When we hit the first mismatched operator, we go back + // and patch the load. Since LCC's operand stack should be at 0 depth by the + // time we hit a branch, this should work fairly well. FIXME FIXME FIXME. + assertInteger(opStackDepth-1); + opStackLoadInstructionAddr[opStackDepth-1] = &buf[ compiledOfs ]; + Inst( "lwzx", PPC_LWZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );// load from memory base + opStackRegType[opStackDepth-1] = 1; break; case OP_LOAD2: - ltop(); // get value from opstack - //Inst( PPC_AND, R_MEMMASK, R_TOP, R_TOP ); // mask it - Inst( PPC_LHZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base - InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); - rtopped = qtrue; + #if DEBUG_VM + if(pass == 1) + printf("%08x LOAD2\n",instruction); + #endif + assertInteger(opStackDepth-1); + opStackLoadInstructionAddr[opStackDepth-1] = 0; + Inst( "lhzx", PPC_LHZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );// load from memory base + opStackRegType[opStackDepth-1] = 1; break; case OP_LOAD1: - ltop(); // get value from opstack - //Inst( PPC_AND, R_MEMMASK, R_TOP, R_TOP ); // mask it - Inst( PPC_LBZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base - InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); - rtopped = qtrue; + #if DEBUG_VM + if(pass == 1) + printf("%08x LOAD1\n",instruction); + #endif + assertInteger(opStackDepth-1); + opStackLoadInstructionAddr[opStackDepth-1] = 0; + Inst( "lbzx", PPC_LBZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );// load from memory base + opStackRegType[opStackDepth-1] = 1; break; case OP_STORE4: - ltopandsecond(); // get value from opstack - //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it - Inst( PPC_STWX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base - rtopped = qfalse; + #if DEBUG_VM + if(pass == 1) + printf("%08x STORE4\n",instruction); + #endif + assertInteger(opStackDepth-2); + if(opStackRegType[opStackDepth-1] == 1) + Inst( "stwx", PPC_STWX, opStackIntRegisters[opStackDepth-1], + opStackIntRegisters[opStackDepth-2], R_MEMBASE ); // store from memory base + else + Inst( "stfsx", PPC_STFSX, opStackFloatRegisters[opStackDepth-1], + opStackIntRegisters[opStackDepth-2], R_MEMBASE ); // store from memory base + opStackRegType[opStackDepth-1] = 0; + opStackRegType[opStackDepth-2] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-2] = 0; + opStackDepth -= 2; break; case OP_STORE2: - ltopandsecond(); // get value from opstack - //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it - Inst( PPC_STHX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base - rtopped = qfalse; + #if DEBUG_VM + if(pass == 1) + printf("%08x STORE2\n",instruction); + #endif + assertInteger(opStackDepth-1); + assertInteger(opStackDepth-2); + Inst( "sthx", PPC_STHX, opStackIntRegisters[opStackDepth-1], + opStackIntRegisters[opStackDepth-2], R_MEMBASE ); // store from memory base + opStackRegType[opStackDepth-1] = 0; + opStackRegType[opStackDepth-2] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-2] = 0; + opStackDepth -= 2; break; case OP_STORE1: - ltopandsecond(); // get value from opstack - //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it - Inst( PPC_STBX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base - rtopped = qfalse; + #if DEBUG_VM + if(pass == 1) + printf("%08x STORE1\n",instruction); + #endif + assertInteger(opStackDepth-1); + assertInteger(opStackDepth-2); + Inst( "stbx", PPC_STBX, opStackIntRegisters[opStackDepth-1], + opStackIntRegisters[opStackDepth-2], R_MEMBASE ); // store from memory base + opStackRegType[opStackDepth-1] = 0; + opStackRegType[opStackDepth-2] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-2] = 0; + opStackDepth -= 2; break; case OP_EQ: - ltopandsecond(); // get value from opstack - Inst( PPC_CMP, 0, R_SECOND, R_TOP ); + #if DEBUG_VM + if(pass == 1) + printf("%08x EQ\n",instruction); + #endif + assertInteger(opStackDepth-1); + assertInteger(opStackDepth-2); + Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackRegType[opStackDepth-2] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-2] = 0; + opStackDepth -= 2; i = Constant4(); jused[i] = 1; - InstImm( PPC_BC, 4, 2, 8 ); + InstImm( "bc", PPC_BC, 4, 2, 8 ); if ( pass==1 ) { v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; } else { v = 0; } - Emit4(PPC_B | (v&0x3ffffff) ); - rtopped = qfalse; + Emit4("b", PPC_B | (v&0x3ffffff) ); break; case OP_NE: - ltopandsecond(); // get value from opstack - Inst( PPC_CMP, 0, R_SECOND, R_TOP ); + #if DEBUG_VM + if(pass == 1) + printf("%08x NE\n",instruction); + #endif + assertInteger(opStackDepth-1); + assertInteger(opStackDepth-2); + Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackRegType[opStackDepth-2] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-2] = 0; + opStackDepth -= 2; i = Constant4(); jused[i] = 1; - InstImm( PPC_BC, 12, 2, 8 ); + InstImm( "bc", PPC_BC, 12, 2, 8 ); if ( pass==1 ) { v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; } else { v = 0; } - Emit4(PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( PPC_BC, 4, 2, v ); + Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); +// InstImm( "bc", PPC_BC, 4, 2, v ); - rtopped = qfalse; break; case OP_LTI: - ltopandsecond(); // get value from opstack - Inst( PPC_CMP, 0, R_SECOND, R_TOP ); + #if DEBUG_VM + if(pass == 1) + printf("%08x LTI\n",instruction); + #endif + assertInteger(opStackDepth-1); + assertInteger(opStackDepth-2); + Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackRegType[opStackDepth-2] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-2] = 0; + opStackDepth -= 2; i = Constant4(); jused[i] = 1; - InstImm( PPC_BC, 4, 0, 8 ); + InstImm( "bc", PPC_BC, 4, 0, 8 ); if ( pass==1 ) { v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; } else { v = 0; } - Emit4(PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( PPC_BC, 12, 0, v ); - rtopped = qfalse; + Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); +// InstImm( "bc", PPC_BC, 12, 0, v ); break; case OP_LEI: - ltopandsecond(); // get value from opstack - Inst( PPC_CMP, 0, R_SECOND, R_TOP ); + #if DEBUG_VM + if(pass == 1) + printf("%08x LEI\n",instruction); + #endif + assertInteger(opStackDepth-1); + assertInteger(opStackDepth-2); + Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackRegType[opStackDepth-2] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-2] = 0; + opStackDepth -= 2; i = Constant4(); jused[i] = 1; - InstImm( PPC_BC, 12, 1, 8 ); + InstImm( "bc", PPC_BC, 12, 1, 8 ); if ( pass==1 ) { v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; } else { v = 0; } - Emit4(PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( PPC_BC, 4, 1, v ); - rtopped = qfalse; + Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); +// InstImm( "bc", PPC_BC, 4, 1, v ); break; case OP_GTI: - ltopandsecond(); // get value from opstack - Inst( PPC_CMP, 0, R_SECOND, R_TOP ); + #if DEBUG_VM + if(pass == 1) + printf("%08x GTI\n",instruction); + #endif + assertInteger(opStackDepth-1); + assertInteger(opStackDepth-2); + Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackRegType[opStackDepth-2] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-2] = 0; + opStackDepth -= 2; i = Constant4(); jused[i] = 1; - InstImm( PPC_BC, 4, 1, 8 ); + InstImm( "bc", PPC_BC, 4, 1, 8 ); if ( pass==1 ) { v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; } else { v = 0; } - Emit4(PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( PPC_BC, 12, 1, v ); - rtopped = qfalse; + Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); +// InstImm( "bc", PPC_BC, 12, 1, v ); break; case OP_GEI: - ltopandsecond(); // get value from opstack - Inst( PPC_CMP, 0, R_SECOND, R_TOP ); + #if DEBUG_VM + if(pass == 1) + printf("%08x GEI\n",instruction); + #endif + assertInteger(opStackDepth-1); + assertInteger(opStackDepth-2); + Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackRegType[opStackDepth-2] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-2] = 0; + opStackDepth -= 2; i = Constant4(); jused[i] = 1; - InstImm( PPC_BC, 12, 0, 8 ); + InstImm( "bc", PPC_BC, 12, 0, 8 ); if ( pass==1 ) { v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; } else { v = 0; } - Emit4(PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( PPC_BC, 4, 0, v ); - rtopped = qfalse; + Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); +// InstImm( "bc", PPC_BC, 4, 0, v ); break; case OP_LTU: - ltopandsecond(); // get value from opstack - Inst( PPC_CMPL, 0, R_SECOND, R_TOP ); + #if DEBUG_VM + if(pass == 1) + printf("%08x LTU\n",instruction); + #endif + assertInteger(opStackDepth-1); + assertInteger(opStackDepth-2); + Inst( "cmpl", PPC_CMPL, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackRegType[opStackDepth-2] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-2] = 0; + opStackDepth -= 2; i = Constant4(); jused[i] = 1; - InstImm( PPC_BC, 4, 0, 8 ); + InstImm( "bc", PPC_BC, 4, 0, 8 ); if ( pass==1 ) { v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; } else { v = 0; } - Emit4(PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( PPC_BC, 12, 0, v ); - rtopped = qfalse; + Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); +// InstImm( "bc", PPC_BC, 12, 0, v ); break; case OP_LEU: - ltopandsecond(); // get value from opstack - Inst( PPC_CMPL, 0, R_SECOND, R_TOP ); + #if DEBUG_VM + if(pass == 1) + printf("%08x LEU\n",instruction); + #endif + assertInteger(opStackDepth-1); + assertInteger(opStackDepth-2); + Inst( "cmpl", PPC_CMPL, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackRegType[opStackDepth-2] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-2] = 0; + opStackDepth -= 2; i = Constant4(); jused[i] = 1; - InstImm( PPC_BC, 12, 1, 8 ); + InstImm( "bc", PPC_BC, 12, 1, 8 ); if ( pass==1 ) { v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; } else { v = 0; } - Emit4(PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( PPC_BC, 4, 1, v ); - rtopped = qfalse; + Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); +// InstImm( "bc", PPC_BC, 4, 1, v ); break; case OP_GTU: - ltopandsecond(); // get value from opstack - Inst( PPC_CMPL, 0, R_SECOND, R_TOP ); + #if DEBUG_VM + if(pass == 1) + printf("%08x GTU\n",instruction); + #endif + assertInteger(opStackDepth-1); + assertInteger(opStackDepth-2); + Inst( "cmpl", PPC_CMPL, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackRegType[opStackDepth-2] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-2] = 0; + opStackDepth -= 2; i = Constant4(); jused[i] = 1; - InstImm( PPC_BC, 4, 1, 8 ); + InstImm( "bc", PPC_BC, 4, 1, 8 ); if ( pass==1 ) { v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; } else { v = 0; } - Emit4(PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( PPC_BC, 12, 1, v ); - rtopped = qfalse; + Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); +// InstImm( "bc", PPC_BC, 12, 1, v ); break; case OP_GEU: - ltopandsecond(); // get value from opstack - Inst( PPC_CMPL, 0, R_SECOND, R_TOP ); + #if DEBUG_VM + if(pass == 1) + printf("%08x GEU\n",instruction); + #endif + assertInteger(opStackDepth-1); + assertInteger(opStackDepth-2); + Inst( "cmpl", PPC_CMPL, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackRegType[opStackDepth-2] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-2] = 0; + opStackDepth -= 2; i = Constant4(); jused[i] = 1; - InstImm( PPC_BC, 12, 0, 8 ); + InstImm( "bc", PPC_BC, 12, 0, 8 ); if ( pass==1 ) { v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; } else { v = 0; } - Emit4(PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( PPC_BC, 4, 0, v ); - rtopped = qfalse; + Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); +// InstImm( "bc", PPC_BC, 4, 0, v ); break; case OP_EQF: - fltopandsecond(); // get value from opstack - Inst( PPC_FCMPU, 0, R_TOP, R_SECOND ); + #if DEBUG_VM + if(pass == 1) + printf("%08x EQF\n",instruction); + #endif + makeFloat(opStackDepth-1); + makeFloat(opStackDepth-2); + Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackRegType[opStackDepth-2] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-2] = 0; + opStackDepth -= 2; i = Constant4(); jused[i] = 1; - InstImm( PPC_BC, 4, 2, 8 ); + InstImm( "bc", PPC_BC, 4, 2, 8 ); if ( pass==1 ) { v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; } else { v = 0; } - Emit4(PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( PPC_BC, 12, 2, v ); - rtopped = qfalse; + Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); +// InstImm( "bc", PPC_BC, 12, 2, v ); break; case OP_NEF: - fltopandsecond(); // get value from opstack - Inst( PPC_FCMPU, 0, R_TOP, R_SECOND ); + #if DEBUG_VM + if(pass == 1) + printf("%08x NEF\n",instruction); + #endif + makeFloat(opStackDepth-1); + makeFloat(opStackDepth-2); + Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackRegType[opStackDepth-2] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-2] = 0; + opStackDepth -= 2; i = Constant4(); jused[i] = 1; - InstImm( PPC_BC, 12, 2, 8 ); + InstImm( "bc", PPC_BC, 12, 2, 8 ); if ( pass==1 ) { v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; } else { v = 0; } - Emit4(PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( PPC_BC, 4, 2, v ); - rtopped = qfalse; + Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); +// InstImm( "bc", PPC_BC, 4, 2, v ); break; case OP_LTF: - fltopandsecond(); // get value from opstack - Inst( PPC_FCMPU, 0, R_SECOND, R_TOP ); + #if DEBUG_VM + if(pass == 1) + printf("%08x LTF\n",instruction); + #endif + makeFloat(opStackDepth-1); + makeFloat(opStackDepth-2); + Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackRegType[opStackDepth-2] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-2] = 0; + opStackDepth -= 2; i = Constant4(); jused[i] = 1; - InstImm( PPC_BC, 4, 0, 8 ); + InstImm( "bc", PPC_BC, 4, 0, 8 ); if ( pass==1 ) { v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; } else { v = 0; } - Emit4(PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( PPC_BC, 12, 0, v ); - rtopped = qfalse; + Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); +// InstImm( "bc", PPC_BC, 12, 0, v ); break; case OP_LEF: - fltopandsecond(); // get value from opstack - Inst( PPC_FCMPU, 0, R_SECOND, R_TOP ); + #if DEBUG_VM + if(pass == 1) + printf("%08x LEF\n",instruction); + #endif + makeFloat(opStackDepth-1); + makeFloat(opStackDepth-2); + Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackRegType[opStackDepth-2] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-2] = 0; + opStackDepth -= 2; i = Constant4(); jused[i] = 1; - InstImm( PPC_BC, 12, 1, 8 ); + InstImm( "bc", PPC_BC, 12, 1, 8 ); if ( pass==1 ) { v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; } else { v = 0; } - Emit4(PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( PPC_BC, 4, 1, v ); - rtopped = qfalse; + Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); +// InstImm( "bc", PPC_BC, 4, 1, v ); break; case OP_GTF: - fltopandsecond(); // get value from opstack - Inst( PPC_FCMPU, 0, R_SECOND, R_TOP ); + #if DEBUG_VM + if(pass == 1) + printf("%08x GTF\n",instruction); + #endif + makeFloat(opStackDepth-1); + makeFloat(opStackDepth-2); + Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackRegType[opStackDepth-2] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-2] = 0; + opStackDepth -= 2; i = Constant4(); jused[i] = 1; - InstImm( PPC_BC, 4, 1, 8 ); + InstImm( "bc", PPC_BC, 4, 1, 8 ); if ( pass==1 ) { v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; } else { v = 0; } - Emit4(PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( PPC_BC, 12, 1, v ); - rtopped = qfalse; + Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); +// InstImm( "bc", PPC_BC, 12, 1, v ); break; case OP_GEF: - fltopandsecond(); // get value from opstack - Inst( PPC_FCMPU, 0, R_SECOND, R_TOP ); + #if DEBUG_VM + if(pass == 1) + printf("%08x GEF\n",instruction); + #endif + makeFloat(opStackDepth-1); + makeFloat(opStackDepth-2); + Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackRegType[opStackDepth-2] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-2] = 0; + opStackDepth -= 2; i = Constant4(); jused[i] = 1; - InstImm( PPC_BC, 12, 0, 8 ); + InstImm( "bc", PPC_BC, 12, 0, 8 ); if ( pass==1 ) { v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; } else { v = 0; } - Emit4(PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( PPC_BC, 4, 0, v ); - rtopped = qfalse; + Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); +// InstImm( "bc", PPC_BC, 4, 0, v ); break; case OP_NEGI: - ltop(); // get value from opstack - InstImm( PPC_SUBFIC, R_TOP, R_TOP, 0 ); - InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack - rtopped = qtrue; + #if DEBUG_VM + if(pass == 1) + printf("%08x NEGI\n",instruction); + #endif + assertInteger(opStackDepth-1); + InstImm( "subfic", PPC_SUBFIC, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0 ); + opStackLoadInstructionAddr[opStackDepth-1] = 0; break; case OP_ADD: - ltop(); // get value from opstack - InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack - Inst( PPC_ADD, R_TOP, R_TOP, R_SECOND ); - InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack - rtopped = qtrue; + #if DEBUG_VM + if(pass == 1) + printf("%08x ADD\n",instruction); + #endif + assertInteger(opStackDepth-1); + assertInteger(opStackDepth-2); + Inst( "add", PPC_ADD, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-2] ); + opStackRegType[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackDepth -= 1; break; case OP_SUB: - ltop(); // get value from opstack - InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack - Inst( PPC_SUBF, R_TOP, R_TOP, R_SECOND ); - InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack - rtopped = qtrue; + #if DEBUG_VM + if(pass == 1) + printf("%08x SUB\n",instruction); + #endif + assertInteger(opStackDepth-1); + assertInteger(opStackDepth-2); + Inst( "subf", PPC_SUBF, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-2] ); + opStackRegType[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackDepth -= 1; break; case OP_DIVI: - ltop(); // get value from opstack - InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack - Inst( PPC_DIVW, R_TOP, R_SECOND, R_TOP ); - InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack - rtopped = qtrue; + #if DEBUG_VM + if(pass == 1) + printf("%08x DIVI\n",instruction); + #endif + assertInteger(opStackDepth-1); + assertInteger(opStackDepth-2); + Inst( "divw", PPC_DIVW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackDepth -= 1; break; case OP_DIVU: - ltop(); // get value from opstack - InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack - Inst( PPC_DIVWU, R_TOP, R_SECOND, R_TOP ); - InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack - rtopped = qtrue; + #if DEBUG_VM + if(pass == 1) + printf("%08x DIVU\n",instruction); + #endif + assertInteger(opStackDepth-1); + assertInteger(opStackDepth-2); + Inst( "divwu", PPC_DIVWU, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackDepth -= 1; break; case OP_MODI: - ltop(); // get value from opstack - InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack - Inst( PPC_DIVW, R_EA, R_SECOND, R_TOP ); - Inst( PPC_MULLW, R_EA, R_TOP, R_EA ); - Inst( PPC_SUBF, R_TOP, R_EA, R_SECOND ); - InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack - rtopped = qtrue; + #if DEBUG_VM + if(pass == 1) + printf("%08x MODI\n",instruction); + #endif + assertInteger(opStackDepth-1); + assertInteger(opStackDepth-2); + Inst( "divw", PPC_DIVW, R_EA, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); + Inst( "mullw", PPC_MULLW, R_EA, opStackIntRegisters[opStackDepth-1], R_EA ); + Inst( "subf", PPC_SUBF, opStackIntRegisters[opStackDepth-2], R_EA, opStackIntRegisters[opStackDepth-2] ); + opStackRegType[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackDepth -= 1; break; case OP_MODU: - ltop(); // get value from opstack - InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack - Inst( PPC_DIVWU, R_EA, R_SECOND, R_TOP ); - Inst( PPC_MULLW, R_EA, R_TOP, R_EA ); - Inst( PPC_SUBF, R_TOP, R_EA, R_SECOND ); - InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack - rtopped = qtrue; + #if DEBUG_VM + if(pass == 1) + printf("%08x MODU\n",instruction); + #endif + assertInteger(opStackDepth-1); + assertInteger(opStackDepth-2); + Inst( "divwu", PPC_DIVWU, R_EA, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); + Inst( "mullw", PPC_MULLW, R_EA, opStackIntRegisters[opStackDepth-1], R_EA ); + Inst( "subf", PPC_SUBF, opStackIntRegisters[opStackDepth-2], R_EA, opStackIntRegisters[opStackDepth-2] ); + opStackRegType[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackDepth -= 1; break; case OP_MULI: case OP_MULU: - ltop(); // get value from opstack - InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack - Inst( PPC_MULLW, R_TOP, R_SECOND, R_TOP ); - InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack - rtopped = qtrue; + #if DEBUG_VM + if(pass == 1) + printf("%08x MULI\n",instruction); + #endif + assertInteger(opStackDepth-1); + assertInteger(opStackDepth-2); + Inst( "mullw", PPC_MULLW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-2] ); + opStackRegType[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackDepth -= 1; break; case OP_BAND: - ltop(); // get value from opstack - InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack - Inst( PPC_AND, R_SECOND, R_TOP, R_TOP ); - InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack - rtopped = qtrue; + #if DEBUG_VM + if(pass == 1) + printf("%08x BAND\n",instruction); + #endif + assertInteger(opStackDepth-1); + assertInteger(opStackDepth-2); + Inst( "and", PPC_AND, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackDepth -= 1; break; case OP_BOR: - ltop(); // get value from opstack - InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack - Inst( PPC_OR, R_SECOND, R_TOP, R_TOP ); - InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack - rtopped = qtrue; + #if DEBUG_VM + if(pass == 1) + printf("%08x BOR\n",instruction); + #endif + assertInteger(opStackDepth-1); + assertInteger(opStackDepth-2); + Inst( "or", PPC_OR, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackDepth -= 1; break; case OP_BXOR: - ltop(); // get value from opstack - InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack - Inst( PPC_XOR, R_SECOND, R_TOP, R_TOP ); - InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack - rtopped = qtrue; + #if DEBUG_VM + if(pass == 1) + printf("%08x BXOR\n",instruction); + #endif + assertInteger(opStackDepth-1); + assertInteger(opStackDepth-2); + Inst( "xor", PPC_XOR, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackDepth -= 1; break; case OP_BCOM: - ltop(); // get value from opstack - Inst( PPC_NOR, R_TOP, R_TOP, R_TOP ); - InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack - rtopped = qtrue; + #if DEBUG_VM + if(pass == 1) + printf("%08x BCOM\n",instruction); + #endif + assertInteger(opStackDepth-1); + Inst( "nor", PPC_NOR, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1] ); + opStackLoadInstructionAddr[opStackDepth-1] = 0; break; case OP_LSH: - ltop(); // get value from opstack - InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack - Inst( PPC_SLW, R_SECOND, R_TOP, R_TOP ); - InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack - rtopped = qtrue; + #if DEBUG_VM + if(pass == 1) + printf("%08x LSH\n",instruction); + #endif + assertInteger(opStackDepth-1); + assertInteger(opStackDepth-2); + Inst( "slw", PPC_SLW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackDepth -= 1; break; case OP_RSHI: - ltop(); // get value from opstack - InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack - Inst( PPC_SRAW, R_SECOND, R_TOP, R_TOP ); - InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack - rtopped = qtrue; + #if DEBUG_VM + if(pass == 1) + printf("%08x RSHI\n",instruction); + #endif + assertInteger(opStackDepth-1); + assertInteger(opStackDepth-2); + Inst( "sraw", PPC_SRAW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackDepth -= 1; break; case OP_RSHU: - ltop(); // get value from opstack - InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack - Inst( PPC_SRW, R_SECOND, R_TOP, R_TOP ); - InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack - rtopped = qtrue; + #if DEBUG_VM + if(pass == 1) + printf("%08x RSHU\n",instruction); + #endif + assertInteger(opStackDepth-1); + assertInteger(opStackDepth-2); + Inst( "srw", PPC_SRW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackDepth -= 1; break; case OP_NEGF: - InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack - Inst( PPC_FNEG, R_TOP, 0, R_TOP ); - InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 ); // save value to opstack - rtopped = qfalse; + #if DEBUG_VM + if(pass == 1) + printf("%08x NEGF\n",instruction); + #endif + makeFloat(opStackDepth-1); + Inst( "fneg", PPC_FNEG, opStackFloatRegisters[opStackDepth-1], 0, opStackFloatRegisters[opStackDepth-1] ); + opStackLoadInstructionAddr[opStackDepth-1] = 0; break; case OP_ADDF: - InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack - InstImm( PPC_LFSU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack - Inst( PPC_FADDS, R_TOP, R_SECOND, R_TOP ); - InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 ); // save value to opstack - rtopped = qfalse; + #if DEBUG_VM + if(pass == 1) + printf("%08x ADDF\n",instruction); + #endif + makeFloat(opStackDepth-1); + makeFloat(opStackDepth-2); + Inst( "fadds", PPC_FADDS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackDepth -= 1; break; case OP_SUBF: - InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack - InstImm( PPC_LFSU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack - Inst( PPC_FSUBS, R_TOP, R_SECOND, R_TOP ); - InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 ); // save value to opstack - rtopped = qfalse; + #if DEBUG_VM + if(pass == 1) + printf("%08x SUBF\n",instruction); + #endif + makeFloat(opStackDepth-1); + makeFloat(opStackDepth-2); + Inst( "fsubs", PPC_FSUBS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackDepth -= 1; break; case OP_DIVF: - InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack - InstImm( PPC_LFSU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack - Inst( PPC_FDIVS, R_TOP, R_SECOND, R_TOP ); - InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 ); // save value to opstack - rtopped = qfalse; + #if DEBUG_VM + if(pass == 1) + printf("%08x DIVF\n",instruction); + #endif + makeFloat(opStackDepth-1); + makeFloat(opStackDepth-2); + Inst( "fdivs", PPC_FDIVS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackDepth -= 1; break; case OP_MULF: - InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack - InstImm( PPC_LFSU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack - Inst4( PPC_FMULS, R_TOP, R_SECOND, 0, R_TOP ); - InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 ); // save value to opstack - rtopped = qfalse; + #if DEBUG_VM + if(pass == 1) + printf("%08x MULF\n",instruction); + #endif + makeFloat(opStackDepth-1); + makeFloat(opStackDepth-2); + Inst4( "fmuls", PPC_FMULS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], 0, opStackFloatRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackDepth -= 1; break; case OP_CVIF: + #if DEBUG_VM + if(pass == 1) + printf("%08x CVIF\n",instruction); + #endif + assertInteger(opStackDepth-1); + //makeInteger(opStackDepth-1); v = (int)&itofConvert; - InstImmU( PPC_ADDIS, R_EA, 0, (v >> 16)&0xffff ); - InstImmU( PPC_ORI, R_EA, R_EA, v & 0xffff ); - InstImm( PPC_LWZ, R_TOP, R_OPSTACK, 0 ); // get value from opstack - InstImmU( PPC_XORIS, R_TOP, R_TOP, 0x8000 ); - InstImm( PPC_STW, R_TOP, R_EA, 12 ); - InstImm( PPC_LFD, R_TOP, R_EA, 0 ); - InstImm( PPC_LFD, R_SECOND, R_EA, 8 ); - Inst( PPC_FSUB, R_TOP, R_SECOND, R_TOP ); + InstImmU( "addis", PPC_ADDIS, R_EA, 0, (v >> 16)&0xffff ); + InstImmU( "ori", PPC_ORI, R_EA, R_EA, v & 0xffff ); + InstImmU( "xoris", PPC_XORIS, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0x8000 ); + InstImm( "stw", PPC_STW, opStackIntRegisters[opStackDepth-1], R_EA, 12 ); + InstImm( "lfd", PPC_LFD, opStackFloatRegisters[opStackDepth-1], R_EA, 0 ); + Inst( "ori", PPC_ORI, 0, 0, 0); + Inst( "ori", PPC_ORI, 0, 0, 0); + Inst( "ori", PPC_ORI, 0, 0, 0); + InstImm( "lfd", PPC_LFD, 13, R_EA, 8 ); + Inst( "fsub", PPC_FSUB, opStackFloatRegisters[opStackDepth-1], 13, opStackFloatRegisters[opStackDepth-1] ); + opStackRegType[opStackDepth-1] = 2; + opStackLoadInstructionAddr[opStackDepth-1] = 0; // Inst( PPC_FRSP, R_TOP, 0, R_TOP ); - InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 ); // save value to opstack - rtopped = qfalse; break; case OP_CVFI: - InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack - Inst( PPC_FCTIWZ, R_TOP, 0, R_TOP ); - Inst( PPC_STFIWX, R_TOP, 0, R_OPSTACK ); // save value to opstack - rtopped = qfalse; + #if DEBUG_VM + if(pass == 1) + printf("%08x CVFI\n",instruction); + #endif + makeFloat(opStackDepth-1); + + InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, opStackDepth*4); + + Inst( "fctiwz", PPC_FCTIWZ, opStackFloatRegisters[opStackDepth-1], 0, opStackFloatRegisters[opStackDepth-1] ); + Inst( "stfiwx", PPC_STFIWX, opStackFloatRegisters[opStackDepth-1], 0, R_OPSTACK ); // save value to opstack (dummy area now) + Inst( "ori", PPC_ORI, 0, 0, 0); + Inst( "ori", PPC_ORI, 0, 0, 0); + Inst( "ori", PPC_ORI, 0, 0, 0); + Inst( "ori", PPC_ORI, 0, 0, 0); + InstImm( "lwz", PPC_LWZ, opStackIntRegisters[opStackDepth-1], R_OPSTACK, 0 ); + + InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, -opStackDepth*4); + + opStackRegType[opStackDepth-1] = 1; + opStackLoadInstructionAddr[opStackDepth-1] = 0; break; case OP_SEX8: - ltop(); // get value from opstack - Inst( PPC_EXTSB, R_TOP, R_TOP, 0 ); - InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); - rtopped = qtrue; + #if DEBUG_VM + if(pass == 1) + printf("%08x SEX8\n",instruction); + #endif + assertInteger(opStackDepth-1); + Inst( "extsb", PPC_EXTSB, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0 ); + opStackLoadInstructionAddr[opStackDepth-1] = 0; break; case OP_SEX16: - ltop(); // get value from opstack - Inst( PPC_EXTSH, R_TOP, R_TOP, 0 ); - InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); - rtopped = qtrue; + #if DEBUG_VM + if(pass == 1) + printf("%08x SEX16\n",instruction); + #endif + assertInteger(opStackDepth-1); + Inst( "extsh", PPC_EXTSH, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0 ); + opStackLoadInstructionAddr[opStackDepth-1] = 0; break; case OP_BLOCK_COPY: v = Constant4() >> 2; - ltop(); // source - InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, -4 ); // dest - InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 ); - InstImmU( PPC_ADDI, R_EA, 0, v ); // count + #if DEBUG_VM + if(pass == 1) + printf("%08x BLOCK_COPY\t%08lx\n",instruction,v<<2); + #endif + assert(opStackDepth >= 2); + assertInteger(opStackDepth-1); + assertInteger(opStackDepth-2); + InstImmU( "addi", PPC_ADDI, R_EA, 0, v ); // count // FIXME: range check - Inst( PPC_MTSPR, R_EA, 9, 0 ); // move to count register - - Inst( PPC_ADD, R_TOP, R_TOP, R_MEMBASE ); - InstImm( PPC_ADDI, R_TOP, R_TOP, -4 ); - Inst( PPC_ADD, R_SECOND, R_SECOND, R_MEMBASE ); - InstImm( PPC_ADDI, R_SECOND, R_SECOND, -4 ); - - InstImm( PPC_LWZU, R_EA, R_TOP, 4 ); // source - InstImm( PPC_STWU, R_EA, R_SECOND, 4 ); // dest - Inst( PPC_BC | 0xfff8 , 16, 0, 0 ); // loop - rtopped = qfalse; + Inst( "mtctr", PPC_MTSPR, R_EA, 9, 0 ); // move to count register + + Inst( "add", PPC_ADD, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE ); + InstImm( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], -4 ); + Inst( "add", PPC_ADD, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], R_MEMBASE ); + InstImm( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], -4 ); + + InstImm( "lwzu", PPC_LWZU, R_EA, opStackIntRegisters[opStackDepth-1], 4 ); // source + InstImm( "stwu", PPC_STWU, R_EA, opStackIntRegisters[opStackDepth-2], 4 ); // dest + Inst( "b", PPC_BC | 0xfff8 , 16, 0, 0 ); // loop + opStackRegType[opStackDepth-1] = 0; + opStackRegType[opStackDepth-2] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-2] = 0; + opStackDepth -= 2; break; case OP_JUMP: - ltop(); // get value from opstack - InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 ); - Inst( PPC_RLWINM | ( 29 << 1 ), R_TOP, R_TOP, 2 ); + #if DEBUG_VM + if(pass == 1) + printf("%08x JUMP\n",instruction); + #endif + assert(opStackDepth == 1); + assertInteger(opStackDepth-1); + + Inst( "rlwinm", PPC_RLWINM | ( 29 << 1 ), opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 2 ); // FIXME: range check - Inst( PPC_LWZX, R_TOP, R_TOP, R_INSTRUCTIONS ); - Inst( PPC_MTSPR, R_TOP, 9, 0 ); // move to count register - Inst( PPC_BCCTR, 20, 0, 0 ); // jump to the count register - rtopped = qfalse; + Inst( "lwzx", PPC_LWZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_INSTRUCTIONS ); + Inst( "mtctr", PPC_MTSPR, opStackIntRegisters[opStackDepth-1], 9, 0 ); // move to count register + Inst( "bctr", PPC_BCCTR, 20, 0, 0 ); // jump to the count register + opStackRegType[opStackDepth-1] = 0; + opStackLoadInstructionAddr[opStackDepth-1] = 0; + opStackDepth -= 1; break; default: Com_Error( ERR_DROP, "VM_CompilePPC: bad opcode %i at instruction %i, offset %i", op, instruction, pc ); } pop0 = pop1; pop1 = op; + assert(opStackDepth >= 0); + assert(opStackDepth < OP_STACK_MAX_DEPTH); + + //printf("%4d\t%s\n",opStackDepth,opnames[op]); } Com_Printf( "VM file %s pass %d compiled to %i bytes of code\n", vm->name, (pass+1), compiledOfs*4 ); @@ -1141,16 +1712,33 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { vm->codeLength = compiledOfs * 4; vm->codeBase = Hunk_Alloc( vm->codeLength, h_low ); Com_Memcpy( vm->codeBase, buf, vm->codeLength ); + + //printf("codeBase: %p\n",vm->codeBase); + Z_Free( buf ); // offset all the instruction pointers for the new location for ( i = 0 ; i < header->instructionCount ; i++ ) { vm->instructionPointers[i] += (int)vm->codeBase; + //printf("%08x %08lx\n",i,vm->instructionPointers[i]); } // go back over it in place now to fixup reletive jump targets buf = (unsigned *)vm->codeBase; - } + } else if ( pass == 1 ) { + #ifdef MACOS_X + // On Mac OS X, the following library routine clears the instruction cache for generated code + MakeDataExecutable(vm->codeBase, vm->codeLength); + #else + #warning Need to clear the instruction cache for generated code + #endif + } + } + if(0) + { + char buf[256]; + printf("wait..\n"); + gets(buf); } Z_Free( jused ); } @@ -1170,6 +1758,9 @@ int VM_CallCompiled( vm_t *vm, int *args ) { currentVM = vm; + //printf("VM_CallCompiled: %p %08lx %08lx %08lx\n", + // vm, args[0],args[1],args[2]); + // interpret the code vm->currentlyInterpreting = qtrue; @@ -1194,6 +1785,7 @@ int VM_CallCompiled( vm_t *vm, int *args ) { *(int *)&image[ programStack + 4 ] = 0; // return stack *(int *)&image[ programStack ] = -1; // will terminate the loop on return + // Cheesy... manually save registers used by VM call... // off we go into generated code... // the PPC calling standard says the parms will all go into R3 - R11, so // no special asm code is needed here @@ -1246,7 +1838,7 @@ asm ( #if defined(MACOS_X) && defined(__OPTIMIZE__) // On Mac OS X, gcc doesn't push a frame when we are optimized, so trying to tear it down results in grave disorder. -#warning Mac OS X optimization on, not popping GCC AsmCall frame +//#warning Mac OS X optimization on, not popping GCC AsmCall frame #else // Mac OS X Server and unoptimized compiles include a GCC AsmCall frame asm ( @@ -1309,7 +1901,7 @@ asm ( // save off the return value " stwu r12,4(r4) \n" // RG_TOP, 0(RG_OPSTACK) - // GCC adds its own prolog / epilog code + // GCC adds its own prolog / epliog code ); } #else diff --git a/src/qcommon/vm_ppc_new.c b/src/qcommon/vm_ppc_new.c deleted file mode 100644 index 79fc506f..00000000 --- a/src/qcommon/vm_ppc_new.c +++ /dev/null @@ -1,2072 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// vm_ppc.c -// ppc dynamic compiler - -#include "vm_local.h" - -#ifdef MACOS_X -#include <CoreServices/CoreServices.h> -#endif - -#define DEBUG_VM 0 - -#if DEBUG_VM -static char *opnames[256] = { - "OP_UNDEF", - - "OP_IGNORE", - - "OP_BREAK", - - "OP_ENTER", - "OP_LEAVE", - "OP_CALL", - "OP_PUSH", - "OP_POP", - - "OP_CONST", - - "OP_LOCAL", - - "OP_JUMP", - - //------------------- - - "OP_EQ", - "OP_NE", - - "OP_LTI", - "OP_LEI", - "OP_GTI", - "OP_GEI", - - "OP_LTU", - "OP_LEU", - "OP_GTU", - "OP_GEU", - - "OP_EQF", - "OP_NEF", - - "OP_LTF", - "OP_LEF", - "OP_GTF", - "OP_GEF", - - //------------------- - - "OP_LOAD1", - "OP_LOAD2", - "OP_LOAD4", - "OP_STORE1", - "OP_STORE2", - "OP_STORE4", - "OP_ARG", - - "OP_BLOCK_COPY", - - //------------------- - - "OP_SEX8", - "OP_SEX16", - - "OP_NEGI", - "OP_ADD", - "OP_SUB", - "OP_DIVI", - "OP_DIVU", - "OP_MODI", - "OP_MODU", - "OP_MULI", - "OP_MULU", - - "OP_BAND", - "OP_BOR", - "OP_BXOR", - "OP_BCOM", - - "OP_LSH", - "OP_RSHI", - "OP_RSHU", - - "OP_NEGF", - "OP_ADDF", - "OP_SUBF", - "OP_DIVF", - "OP_MULF", - - "OP_CVIF", - "OP_CVFI" -}; -#endif - -typedef enum { - R_REAL_STACK = 1, - // registers 3-11 are the parameter passing registers - - // state - R_STACK = 3, // local - R_OPSTACK, // global - - // constants - R_MEMBASE, // global - R_MEMMASK, - R_ASMCALL, // global - R_INSTRUCTIONS, // global - R_NUM_INSTRUCTIONS, // global - R_CVM, // currentVM - - // temps - R_TOP = 11, - R_SECOND = 12, - R_EA = 2 // effective address calculation - -} regNums_t; - -#define RG_REAL_STACK r1 -#define RG_STACK r3 -#define RG_OPSTACK r4 -#define RG_MEMBASE r5 -#define RG_MEMMASK r6 -#define RG_ASMCALL r7 -#define RG_INSTRUCTIONS r8 -#define RG_NUM_INSTRUCTIONS r9 -#define RG_CVM r10 -#define RG_TOP r12 -#define RG_SECOND r13 -#define RG_EA r14 - -// The deepest value I saw in the Quake3 games was 9. -#define OP_STACK_MAX_DEPTH 16 - -// These are all volatile and thus must be saved upon entry to the VM code. -// NOTE: These are General Purpose Registers (GPR) numbers like the -// R_ definitions in the regNums_t enum above (31 is the max) -static int opStackIntRegisters[OP_STACK_MAX_DEPTH] = -{ - 16, 17, 18, 19, - 20, 21, 22, 23, - 24, 25, 26, 27, - 28, 29, 30, 31 -}; - -static unsigned int *opStackLoadInstructionAddr[OP_STACK_MAX_DEPTH]; - -// We use different registers for the floating point -// operand stack (these are volatile in the PPC ABI) -// NOTE: these are Floating Point Register (FPR) numbers, not -// General Purpose Register (GPR) numbers -static int opStackFloatRegisters[OP_STACK_MAX_DEPTH] = -{ - 0, 1, 2, 3, - 4, 5, 6, 7, - 8, 9, 10, 11, - 12, 13, 14, 15 -}; - -static int opStackRegType[OP_STACK_MAX_DEPTH] = -{ - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0 -}; - -// this doesn't have the low order bits set for instructions i'm not using... -typedef enum { - PPC_TDI = 0x08000000, - PPC_TWI = 0x0c000000, - PPC_MULLI = 0x1c000000, - PPC_SUBFIC = 0x20000000, - PPC_CMPI = 0x28000000, - PPC_CMPLI = 0x2c000000, - PPC_ADDIC = 0x30000000, - PPC_ADDIC_ = 0x34000000, - PPC_ADDI = 0x38000000, - PPC_ADDIS = 0x3c000000, - PPC_BC = 0x40000000, - PPC_SC = 0x44000000, - PPC_B = 0x48000000, - - PPC_MCRF = 0x4c000000, - PPC_BCLR = 0x4c000020, - PPC_RFID = 0x4c000000, - PPC_CRNOR = 0x4c000000, - PPC_RFI = 0x4c000000, - PPC_CRANDC = 0x4c000000, - PPC_ISYNC = 0x4c000000, - PPC_CRXOR = 0x4c000000, - PPC_CRNAND = 0x4c000000, - PPC_CREQV = 0x4c000000, - PPC_CRORC = 0x4c000000, - PPC_CROR = 0x4c000000, -//------------ - PPC_BCCTR = 0x4c000420, - PPC_RLWIMI = 0x50000000, - PPC_RLWINM = 0x54000000, - PPC_RLWNM = 0x5c000000, - PPC_ORI = 0x60000000, - PPC_ORIS = 0x64000000, - PPC_XORI = 0x68000000, - PPC_XORIS = 0x6c000000, - PPC_ANDI_ = 0x70000000, - PPC_ANDIS_ = 0x74000000, - PPC_RLDICL = 0x78000000, - PPC_RLDICR = 0x78000000, - PPC_RLDIC = 0x78000000, - PPC_RLDIMI = 0x78000000, - PPC_RLDCL = 0x78000000, - PPC_RLDCR = 0x78000000, - PPC_CMP = 0x7c000000, - PPC_TW = 0x7c000000, - PPC_SUBFC = 0x7c000010, - PPC_MULHDU = 0x7c000000, - PPC_ADDC = 0x7c000014, - PPC_MULHWU = 0x7c000000, - PPC_MFCR = 0x7c000000, - PPC_LWAR = 0x7c000000, - PPC_LDX = 0x7c000000, - PPC_LWZX = 0x7c00002e, - PPC_SLW = 0x7c000030, - PPC_CNTLZW = 0x7c000000, - PPC_SLD = 0x7c000000, - PPC_AND = 0x7c000038, - PPC_CMPL = 0x7c000040, - PPC_SUBF = 0x7c000050, - PPC_LDUX = 0x7c000000, -//------------ - PPC_DCBST = 0x7c000000, - PPC_LWZUX = 0x7c00006c, - PPC_CNTLZD = 0x7c000000, - PPC_ANDC = 0x7c000000, - PPC_TD = 0x7c000000, - PPC_MULHD = 0x7c000000, - PPC_MULHW = 0x7c000000, - PPC_MTSRD = 0x7c000000, - PPC_MFMSR = 0x7c000000, - PPC_LDARX = 0x7c000000, - PPC_DCBF = 0x7c000000, - PPC_LBZX = 0x7c0000ae, - PPC_NEG = 0x7c000000, - PPC_MTSRDIN = 0x7c000000, - PPC_LBZUX = 0x7c000000, - PPC_NOR = 0x7c0000f8, - PPC_SUBFE = 0x7c000000, - PPC_ADDE = 0x7c000000, - PPC_MTCRF = 0x7c000000, - PPC_MTMSR = 0x7c000000, - PPC_STDX = 0x7c000000, - PPC_STWCX_ = 0x7c000000, - PPC_STWX = 0x7c00012e, - PPC_MTMSRD = 0x7c000000, - PPC_STDUX = 0x7c000000, - PPC_STWUX = 0x7c00016e, - PPC_SUBFZE = 0x7c000000, - PPC_ADDZE = 0x7c000000, - PPC_MTSR = 0x7c000000, - PPC_STDCX_ = 0x7c000000, - PPC_STBX = 0x7c0001ae, - PPC_SUBFME = 0x7c000000, - PPC_MULLD = 0x7c000000, -//------------ - PPC_ADDME = 0x7c000000, - PPC_MULLW = 0x7c0001d6, - PPC_MTSRIN = 0x7c000000, - PPC_DCBTST = 0x7c000000, - PPC_STBUX = 0x7c000000, - PPC_ADD = 0x7c000214, - PPC_DCBT = 0x7c000000, - PPC_LHZX = 0x7c00022e, - PPC_EQV = 0x7c000000, - PPC_TLBIE = 0x7c000000, - PPC_ECIWX = 0x7c000000, - PPC_LHZUX = 0x7c000000, - PPC_XOR = 0x7c000278, - PPC_MFSPR = 0x7c0002a6, - PPC_LWAX = 0x7c000000, - PPC_LHAX = 0x7c000000, - PPC_TLBIA = 0x7c000000, - PPC_MFTB = 0x7c000000, - PPC_LWAUX = 0x7c000000, - PPC_LHAUX = 0x7c000000, - PPC_STHX = 0x7c00032e, - PPC_ORC = 0x7c000338, - PPC_SRADI = 0x7c000000, - PPC_SLBIE = 0x7c000000, - PPC_ECOWX = 0x7c000000, - PPC_STHUX = 0x7c000000, - PPC_OR = 0x7c000378, - PPC_DIVDU = 0x7c000000, - PPC_DIVWU = 0x7c000396, - PPC_MTSPR = 0x7c0003a6, - PPC_DCBI = 0x7c000000, - PPC_NAND = 0x7c000000, - PPC_DIVD = 0x7c000000, -//------------ - PPC_DIVW = 0x7c0003d6, - PPC_SLBIA = 0x7c000000, - PPC_MCRXR = 0x7c000000, - PPC_LSWX = 0x7c000000, - PPC_LWBRX = 0x7c000000, - PPC_LFSX = 0x7c00042e, - PPC_SRW = 0x7c000430, - PPC_SRD = 0x7c000000, - PPC_TLBSYNC = 0x7c000000, - PPC_LFSUX = 0x7c000000, - PPC_MFSR = 0x7c000000, - PPC_LSWI = 0x7c000000, - PPC_SYNC = 0x7c000000, - PPC_LFDX = 0x7c000000, - PPC_LFDUX = 0x7c000000, - PPC_MFSRIN = 0x7c000000, - PPC_STSWX = 0x7c000000, - PPC_STWBRX = 0x7c000000, - PPC_STFSX = 0x7c00052e, - PPC_STFSUX = 0x7c000000, - PPC_STSWI = 0x7c000000, - PPC_STFDX = 0x7c000000, - PPC_DCBA = 0x7c000000, - PPC_STFDUX = 0x7c000000, - PPC_LHBRX = 0x7c000000, - PPC_SRAW = 0x7c000630, - PPC_SRAD = 0x7c000000, - PPC_SRAWI = 0x7c000000, - PPC_EIEIO = 0x7c000000, - PPC_STHBRX = 0x7c000000, - PPC_EXTSH = 0x7c000734, - PPC_EXTSB = 0x7c000774, - PPC_ICBI = 0x7c000000, -//------------ - PPC_STFIWX = 0x7c0007ae, - PPC_EXTSW = 0x7c000000, - PPC_DCBZ = 0x7c000000, - PPC_LWZ = 0x80000000, - PPC_LWZU = 0x84000000, - PPC_LBZ = 0x88000000, - PPC_LBZU = 0x8c000000, - PPC_STW = 0x90000000, - PPC_STWU = 0x94000000, - PPC_STB = 0x98000000, - PPC_STBU = 0x9c000000, - PPC_LHZ = 0xa0000000, - PPC_LHZU = 0xa4000000, - PPC_LHA = 0xa8000000, - PPC_LHAU = 0xac000000, - PPC_STH = 0xb0000000, - PPC_STHU = 0xb4000000, - PPC_LMW = 0xb8000000, - PPC_STMW = 0xbc000000, - PPC_LFS = 0xc0000000, - PPC_LFSU = 0xc4000000, - PPC_LFD = 0xc8000000, - PPC_LFDU = 0xcc000000, - PPC_STFS = 0xd0000000, - PPC_STFSU = 0xd4000000, - PPC_STFD = 0xd8000000, - PPC_STFDU = 0xdc000000, - PPC_LD = 0xe8000000, - PPC_LDU = 0xe8000001, - PPC_LWA = 0xe8000002, - PPC_FDIVS = 0xec000024, - PPC_FSUBS = 0xec000028, - PPC_FADDS = 0xec00002a, -//------------ - PPC_FSQRTS = 0xec000000, - PPC_FRES = 0xec000000, - PPC_FMULS = 0xec000032, - PPC_FMSUBS = 0xec000000, - PPC_FMADDS = 0xec000000, - PPC_FNMSUBS = 0xec000000, - PPC_FNMADDS = 0xec000000, - PPC_STD = 0xf8000000, - PPC_STDU = 0xf8000001, - PPC_FCMPU = 0xfc000000, - PPC_FRSP = 0xfc000018, - PPC_FCTIW = 0xfc000000, - PPC_FCTIWZ = 0xfc00001e, - PPC_FDIV = 0xfc000000, - PPC_FSUB = 0xfc000028, - PPC_FADD = 0xfc000000, - PPC_FSQRT = 0xfc000000, - PPC_FSEL = 0xfc000000, - PPC_FMUL = 0xfc000000, - PPC_FRSQRTE = 0xfc000000, - PPC_FMSUB = 0xfc000000, - PPC_FMADD = 0xfc000000, - PPC_FNMSUB = 0xfc000000, - PPC_FNMADD = 0xfc000000, - PPC_FCMPO = 0xfc000000, - PPC_MTFSB1 = 0xfc000000, - PPC_FNEG = 0xfc000050, - PPC_MCRFS = 0xfc000000, - PPC_MTFSB0 = 0xfc000000, - PPC_FMR = 0xfc000000, - PPC_MTFSFI = 0xfc000000, - PPC_FNABS = 0xfc000000, - PPC_FABS = 0xfc000000, -//------------ - PPC_MFFS = 0xfc000000, - PPC_MTFSF = 0xfc000000, - PPC_FCTID = 0xfc000000, - PPC_FCTIDZ = 0xfc000000, - PPC_FCFID = 0xfc000000 - -} ppcOpcodes_t; - - -// the newly generated code -static unsigned *buf; -static int compiledOfs; // in dwords -static int pass; - -// fromt the original bytecode -static byte *code; -static int pc; - -void AsmCall( void ); - -double itofConvert[2]; - -static int Constant4( void ) { - int v; - - v = code[pc] | (code[pc+1]<<8) | (code[pc+2]<<16) | (code[pc+3]<<24); - pc += 4; - return v; -} - -static int Constant1( void ) { - int v; - - v = code[pc]; - pc += 1; - return v; -} - -static void Emit4( char *opname, int i ) { - #if DEBUG_VM - if(pass == 1) - printf("\t\t\t%p %s\t%08lx\n",&buf[compiledOfs],opname,i&0x3ffffff); - #endif - buf[ compiledOfs ] = i; - compiledOfs++; -} - -static void Inst( char *opname, int opcode, int destReg, int aReg, int bReg ) { - unsigned r; - - #if DEBUG_VM - if(pass == 1) - printf("\t\t\t%p %s\tr%d,r%d,r%d\n",&buf[compiledOfs],opname,destReg,aReg,bReg); - #endif - r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) ; - buf[ compiledOfs ] = r; - compiledOfs++; -} - -static void Inst4( char *opname, int opcode, int destReg, int aReg, int bReg, int cReg ) { - unsigned r; - - #if DEBUG_VM - if(pass == 1) - printf("\t\t\t%p %s\tr%d,r%d,r%d,r%d\n",&buf[compiledOfs],opname,destReg,aReg,bReg,cReg); - #endif - r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) | ( cReg << 6 ); - buf[ compiledOfs ] = r; - compiledOfs++; -} - -static void InstImm( char *opname, int opcode, int destReg, int aReg, int immediate ) { - unsigned r; - - if ( immediate > 32767 || immediate < -32768 ) { - Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range, opcode %x,%d,%d", immediate, opcode, destReg, aReg ); - } - #if DEBUG_VM - if(pass == 1) - printf("\t\t\t%p %s\tr%d,r%d,0x%x\n",&buf[compiledOfs],opname,destReg,aReg,immediate); - #endif - r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff ); - buf[ compiledOfs ] = r; - compiledOfs++; -} - -static void InstImmU( char *opname, int opcode, int destReg, int aReg, int immediate ) { - unsigned r; - - if ( immediate > 0xffff || immediate < 0 ) { - Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range", immediate ); - } - #if DEBUG_VM - if(pass == 1) - printf("\t\t\t%p %s\tr%d,r%d,0x%x\n",&buf[compiledOfs],opname,destReg,aReg,immediate); - #endif - r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff ); - buf[ compiledOfs ] = r; - compiledOfs++; -} - -static int pop0, pop1, oc0, oc1; -static vm_t *tvm; -static int instruction; -static byte *jused; - -static void spillOpStack(int depth) -{ - // Store out each register on the operand stack to it's correct location. - int i; - - for(i = 0; i < depth; i++) - { - assert(opStackRegType[i]); - assert(opStackRegType[i] == 1); - switch(opStackRegType[i]) - { - case 1: // Integer register - InstImm( "stw", PPC_STW, opStackIntRegisters[i], R_OPSTACK, i*4+4); - break; - case 2: // Float register - InstImm( "stfs", PPC_STFS, opStackFloatRegisters[i], R_OPSTACK, i*4+4); - break; - } - opStackRegType[i] = 0; - } -} - -static void loadOpStack(int depth) -{ - // Back off operand stack pointer and reload all operands. -// InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, -(depth)*4 ); - - int i; - - for(i = 0; i < depth; i++) - { - assert(opStackRegType[i] == 0); - // For now we're stuck reloading everything as an integer. - opStackLoadInstructionAddr[i] = &buf[compiledOfs]; - InstImm( "lwz", PPC_LWZ, opStackIntRegisters[i], R_OPSTACK, i*4+4); - opStackRegType[i] = 1; - } -} - -static void makeFloat(int depth) -{ - //assert(opStackRegType[depth] == 1); - if(opStackRegType[depth] == 1) - { - unsigned instruction; - unsigned destReg, aReg, bReg, imm; - - if(opStackLoadInstructionAddr[depth]) - { - // Repatch load instruction to use LFS instead of LWZ - instruction = *opStackLoadInstructionAddr[depth]; - // Figure out if it's LWZ or LWZX - if((instruction & 0xfc000000) == PPC_LWZ) - { - //printf("patching LWZ at %p to LFS at depth %ld\n",opStackLoadInstructionAddr[depth],depth); - //printf("old instruction: %08lx\n",instruction); - // Extract registers - destReg = (instruction >> 21) & 31; - aReg = (instruction >> 16) & 31; - imm = instruction & 0xffff; - - // Calculate correct FP register to use. - // THIS ASSUMES REGISTER USAGE FOR THE STACK IS n, n+1, n+2, etc! - //printf("old dest: %ld\n",destReg); - destReg = (destReg - opStackIntRegisters[0]) + opStackFloatRegisters[0]; - instruction = PPC_LFS | ( destReg << 21 ) | ( aReg << 16 ) | imm ; - //printf("new dest: %ld\n",destReg); - //printf("new instruction: %08lx\n",instruction); - } - else - { - //printf("patching LWZX at %p to LFSX at depth %ld\n",opStackLoadInstructionAddr[depth],depth); - //printf("old instruction: %08lx\n",instruction); - // Extract registers - destReg = (instruction >> 21) & 31; - aReg = (instruction >> 16) & 31; - bReg = (instruction >> 11) & 31; - // Calculate correct FP register to use. - // THIS ASSUMES REGISTER USAGE FOR THE STACK IS n, n+1, n+2, etc! - //printf("old dest: %ld\n",destReg); - destReg = (destReg - opStackIntRegisters[0]) + opStackFloatRegisters[0]; - instruction = PPC_LFSX | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) ; - //printf("new dest: %ld\n",destReg); - //printf("new instruction: %08lx\n",instruction); - } - *opStackLoadInstructionAddr[depth] = instruction; - opStackLoadInstructionAddr[depth] = 0; - } - else - { - //printf("doing float constant load at %p for depth %ld\n",&buf[compiledOfs],depth); - // It was likely loaded as a constant so we have to save/load it. A more - // interesting implementation might be to generate code to do a "PC relative" - // load from the VM code region. - InstImm( "stw", PPC_STW, opStackIntRegisters[depth], R_OPSTACK, depth*4+4); - // For XXX make sure we force enough NOPs to get the load into - // another dispatch group to avoid pipeline flush. - Inst( "ori", PPC_ORI, 0, 0, 0 ); - Inst( "ori", PPC_ORI, 0, 0, 0 ); - Inst( "ori", PPC_ORI, 0, 0, 0 ); - Inst( "ori", PPC_ORI, 0, 0, 0 ); - InstImm( "lfs", PPC_LFS, opStackFloatRegisters[depth], R_OPSTACK, depth*4+4); - } - opStackRegType[depth] = 2; - } -} - -// TJW: Unused -#if 0 -static void fltop() { - if (rtopped == qfalse) { - InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack - } -} -#endif - -#if 0 -static void fltopandsecond() { - InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack - InstImm( PPC_LFS, R_SECOND, R_OPSTACK, -4 ); // get value from opstack - InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 ); - rtopped = qfalse; - return; -} -#endif - -#define assertInteger(depth) assert(opStackRegType[depth] == 1) - -/* -================= -VM_Compile -================= -*/ -void VM_Compile( vm_t *vm, vmHeader_t *header ) { - int op; - int maxLength; - int v; - int i; - int opStackDepth; - - int mainFunction; - - // set up the into-to-float variables - ((int *)itofConvert)[0] = 0x43300000; - ((int *)itofConvert)[1] = 0x80000000; - ((int *)itofConvert)[2] = 0x43300000; - - // allocate a very large temp buffer, we will shrink it later - maxLength = header->codeLength * 8; - buf = Z_Malloc( maxLength ); - jused = Z_Malloc(header->instructionCount + 2); - Com_Memset(jused, 0, header->instructionCount+2); - - // compile everything twice, so the second pass will have valid instruction - // pointers for branches - for ( pass = -1 ; pass < 2 ; pass++ ) { - - // translate all instructions - pc = 0; - mainFunction = 0; - opStackDepth = 0; - - pop0 = 343545; - pop1 = 2443545; - oc0 = -2343535; - oc1 = 24353454; - tvm = vm; - code = (byte *)header + header->codeOffset; - compiledOfs = 0; -#ifndef __GNUC__ - // metrowerks seems to require this header in front of functions - Emit4( (int)(buf+2) ); - Emit4( 0 ); -#endif - - for ( instruction = 0 ; instruction < header->instructionCount ; instruction++ ) { - if ( compiledOfs*4 > maxLength - 16 ) { - Com_Error( ERR_DROP, "VM_Compile: maxLength exceeded" ); - } - - op = code[ pc ]; - if ( !pass ) { - vm->instructionPointers[ instruction ] = compiledOfs * 4; - } - pc++; - switch ( op ) { - case 0: - break; - case OP_BREAK: - #if DEBUG_VM - if(pass == 1) - printf("%08lx BREAK\n",instruction); - #endif - InstImmU( "addi", PPC_ADDI, R_TOP, 0, 0 ); - InstImm( "lwz", PPC_LWZ, R_TOP, R_TOP, 0 ); // *(int *)0 to crash to debugger - break; - case OP_ENTER: - opStackDepth = 0; - v = Constant4(); - #if DEBUG_VM - if(pass == 1) - printf("%08x ENTER\t%04x\n",instruction,v); - #endif - opStackRegType[opStackDepth] = 0; - mainFunction++; - if(mainFunction == 1) - { - // Main VM entry point is the first thing we compile, so save off operand stack - // registers here. This avoids issues with trying to trick the native compiler - // into doing it, and properly matches the PowerPC ABI - InstImm( "addi", PPC_ADDI, R_REAL_STACK, R_REAL_STACK, -OP_STACK_MAX_DEPTH*4 ); // sub R_STACK, R_STACK, imm - for(i = 0; i < OP_STACK_MAX_DEPTH; i++) - InstImm( "stw", PPC_STW, opStackIntRegisters[i], R_REAL_STACK, i*4); - } - InstImm( "addi", PPC_ADDI, R_STACK, R_STACK, -v ); // sub R_STACK, R_STACK, imm - break; - case OP_CONST: - v = Constant4(); - #if DEBUG_VM - if(pass == 1) - printf("%08x CONST\t%08x\n",instruction,v); - #endif - opStackLoadInstructionAddr[opStackDepth] = 0; - if ( v < 32768 && v >= -32768 ) { - InstImmU( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth], 0, v & 0xffff ); - } else { - InstImmU( "addis", PPC_ADDIS, opStackIntRegisters[opStackDepth], 0, (v >> 16)&0xffff ); - if ( v & 0xffff ) { - InstImmU( "ori", PPC_ORI, opStackIntRegisters[opStackDepth], opStackIntRegisters[opStackDepth], v & 0xffff ); - } - } - opStackRegType[opStackDepth] = 1; - opStackDepth += 1; - if (code[pc] == OP_JUMP) { - jused[v] = 1; - } - break; - case OP_LOCAL: - oc1 = Constant4(); - #if DEBUG_VM - if(pass == 1) - printf("%08x LOCAL\t%08x\n",instruction,oc1); - #endif - if (code[pc] == OP_LOAD4 || code[pc] == OP_LOAD2 || code[pc] == OP_LOAD1) { - oc1 &= vm->dataMask; - } - InstImm( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth], R_STACK, oc1 ); - opStackRegType[opStackDepth] = 1; - opStackLoadInstructionAddr[opStackDepth] = 0; - opStackDepth += 1; - break; - case OP_ARG: - v = Constant1(); - #if DEBUG_VM - if(pass == 1) - printf("%08x ARG \t%08x\n",instruction,v); - #endif - InstImm( "addi", PPC_ADDI, R_EA, R_STACK, v ); // location to put it - if(opStackRegType[opStackDepth-1] == 1) - Inst( "stwx", PPC_STWX, opStackIntRegisters[opStackDepth-1], R_EA, R_MEMBASE ); - else - Inst( "stfsx", PPC_STFSX, opStackFloatRegisters[opStackDepth-1], R_EA, R_MEMBASE ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - - break; - case OP_CALL: - #if DEBUG_VM - if(pass == 1) - printf("%08x CALL\n",instruction); - #endif - assertInteger(opStackDepth-1); - assert(opStackDepth > 0); - Inst( "mflr", PPC_MFSPR, R_SECOND, 8, 0 ); // move from link register - InstImm( "stwu", PPC_STWU, R_SECOND, R_REAL_STACK, -16 ); // save off the old return address - - // Spill operand stack registers. - spillOpStack(opStackDepth); - - // We need to leave R_OPSTACK pointing to the top entry on the stack, which is the call address. - // It will be consumed (and R4 decremented) by the AsmCall code. - InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, opStackDepth*4); - - Inst( "mtctr", PPC_MTSPR, R_ASMCALL, 9, 0 ); // move to count register - Inst( "bctrl", PPC_BCCTR | 1, 20, 0, 0 ); // jump and link to the count register - - // R4 now points to the top of the operand stack, which has the return value in it. We want to - // back off the pointer to point to the base of our local operand stack and then reload the stack. - - InstImm("addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, -opStackDepth*4); - - // Reload operand stack. - loadOpStack(opStackDepth); - - InstImm( "lwz", PPC_LWZ, R_SECOND, R_REAL_STACK, 0 ); // fetch the old return address - InstImm( "addi", PPC_ADDI, R_REAL_STACK, R_REAL_STACK, 16 ); - Inst( "mtlr", PPC_MTSPR, R_SECOND, 8, 0 ); // move to link register - break; - case OP_PUSH: - #if DEBUG_VM - if(pass == 1) - printf("%08x PUSH\n",instruction); - #endif - opStackRegType[opStackDepth] = 1; // Garbage int value. - opStackDepth += 1; - break; - case OP_POP: - #if DEBUG_VM - if(pass == 1) - printf("%08x POP\n",instruction); - #endif - opStackDepth -= 1; - opStackRegType[opStackDepth] = 0; // ?? - opStackLoadInstructionAddr[opStackDepth-1] = 0; - break; - case OP_LEAVE: - #if DEBUG_VM - if(pass == 1) - printf("%08x LEAVE\n",instruction); - #endif - assert(opStackDepth == 1); - assert(opStackRegType[0] != 0); - // Save return value onto top of op stack. We also have to increment R_OPSTACK - switch(opStackRegType[0]) - { - case 1: // Integer register - InstImm( "stw", PPC_STWU, opStackIntRegisters[0], R_OPSTACK, 4); - break; - case 2: // Float register - InstImm( "stfs", PPC_STFSU, opStackFloatRegisters[0], R_OPSTACK, 4); - break; - } - InstImm( "addi", PPC_ADDI, R_STACK, R_STACK, Constant4() ); // add R_STACK, R_STACK, imm - if(mainFunction == 1) - { - for(i = 0; i < OP_STACK_MAX_DEPTH; i++) - InstImm( "lwz", PPC_LWZ, opStackIntRegisters[i], R_REAL_STACK, i*4); - InstImm( "addi", PPC_ADDI, R_REAL_STACK, R_REAL_STACK, OP_STACK_MAX_DEPTH*4 ); - } - opStackDepth--; - opStackRegType[opStackDepth] = 0; - opStackLoadInstructionAddr[opStackDepth] = 0; - Inst( "blr", PPC_BCLR, 20, 0, 0 ); // branch unconditionally to link register - break; - case OP_LOAD4: - #if DEBUG_VM - if(pass == 1) - printf("%08x LOAD4\n",instruction); - #endif - // We should try to figure out whether to use LWZX or LFSX based - // on some kind of code analysis after subsequent passes. I think what - // we could do is store the compiled load instruction address along with - // the register type. When we hit the first mismatched operator, we go back - // and patch the load. Since LCC's operand stack should be at 0 depth by the - // time we hit a branch, this should work fairly well. FIXME FIXME FIXME. - assertInteger(opStackDepth-1); - opStackLoadInstructionAddr[opStackDepth-1] = &buf[ compiledOfs ]; - Inst( "lwzx", PPC_LWZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );// load from memory base - opStackRegType[opStackDepth-1] = 1; - break; - case OP_LOAD2: - #if DEBUG_VM - if(pass == 1) - printf("%08x LOAD2\n",instruction); - #endif - assertInteger(opStackDepth-1); - opStackLoadInstructionAddr[opStackDepth-1] = 0; - Inst( "lhzx", PPC_LHZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );// load from memory base - opStackRegType[opStackDepth-1] = 1; - break; - case OP_LOAD1: - #if DEBUG_VM - if(pass == 1) - printf("%08x LOAD1\n",instruction); - #endif - assertInteger(opStackDepth-1); - opStackLoadInstructionAddr[opStackDepth-1] = 0; - Inst( "lbzx", PPC_LBZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );// load from memory base - opStackRegType[opStackDepth-1] = 1; - break; - case OP_STORE4: - #if DEBUG_VM - if(pass == 1) - printf("%08x STORE4\n",instruction); - #endif - assertInteger(opStackDepth-2); - if(opStackRegType[opStackDepth-1] == 1) - Inst( "stwx", PPC_STWX, opStackIntRegisters[opStackDepth-1], - opStackIntRegisters[opStackDepth-2], R_MEMBASE ); // store from memory base - else - Inst( "stfsx", PPC_STFSX, opStackFloatRegisters[opStackDepth-1], - opStackIntRegisters[opStackDepth-2], R_MEMBASE ); // store from memory base - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - break; - case OP_STORE2: - #if DEBUG_VM - if(pass == 1) - printf("%08x STORE2\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "sthx", PPC_STHX, opStackIntRegisters[opStackDepth-1], - opStackIntRegisters[opStackDepth-2], R_MEMBASE ); // store from memory base - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - break; - case OP_STORE1: - #if DEBUG_VM - if(pass == 1) - printf("%08x STORE1\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "stbx", PPC_STBX, opStackIntRegisters[opStackDepth-1], - opStackIntRegisters[opStackDepth-2], R_MEMBASE ); // store from memory base - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - break; - - case OP_EQ: - #if DEBUG_VM - if(pass == 1) - printf("%08x EQ\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 4, 2, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (v&0x3ffffff) ); - break; - case OP_NE: - #if DEBUG_VM - if(pass == 1) - printf("%08x NE\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 12, 2, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 4, 2, v ); - - break; - case OP_LTI: - #if DEBUG_VM - if(pass == 1) - printf("%08x LTI\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 4, 0, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 12, 0, v ); - break; - case OP_LEI: - #if DEBUG_VM - if(pass == 1) - printf("%08x LEI\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 12, 1, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 4, 1, v ); - break; - case OP_GTI: - #if DEBUG_VM - if(pass == 1) - printf("%08x GTI\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 4, 1, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 12, 1, v ); - break; - case OP_GEI: - #if DEBUG_VM - if(pass == 1) - printf("%08x GEI\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 12, 0, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 4, 0, v ); - break; - case OP_LTU: - #if DEBUG_VM - if(pass == 1) - printf("%08x LTU\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "cmpl", PPC_CMPL, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 4, 0, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 12, 0, v ); - break; - case OP_LEU: - #if DEBUG_VM - if(pass == 1) - printf("%08x LEU\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "cmpl", PPC_CMPL, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 12, 1, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 4, 1, v ); - break; - case OP_GTU: - #if DEBUG_VM - if(pass == 1) - printf("%08x GTU\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "cmpl", PPC_CMPL, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 4, 1, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 12, 1, v ); - break; - case OP_GEU: - #if DEBUG_VM - if(pass == 1) - printf("%08x GEU\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "cmpl", PPC_CMPL, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 12, 0, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 4, 0, v ); - break; - - case OP_EQF: - #if DEBUG_VM - if(pass == 1) - printf("%08x EQF\n",instruction); - #endif - makeFloat(opStackDepth-1); - makeFloat(opStackDepth-2); - Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 4, 2, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 12, 2, v ); - break; - case OP_NEF: - #if DEBUG_VM - if(pass == 1) - printf("%08x NEF\n",instruction); - #endif - makeFloat(opStackDepth-1); - makeFloat(opStackDepth-2); - Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 12, 2, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 4, 2, v ); - break; - case OP_LTF: - #if DEBUG_VM - if(pass == 1) - printf("%08x LTF\n",instruction); - #endif - makeFloat(opStackDepth-1); - makeFloat(opStackDepth-2); - Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 4, 0, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 12, 0, v ); - break; - case OP_LEF: - #if DEBUG_VM - if(pass == 1) - printf("%08x LEF\n",instruction); - #endif - makeFloat(opStackDepth-1); - makeFloat(opStackDepth-2); - Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 12, 1, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 4, 1, v ); - break; - case OP_GTF: - #if DEBUG_VM - if(pass == 1) - printf("%08x GTF\n",instruction); - #endif - makeFloat(opStackDepth-1); - makeFloat(opStackDepth-2); - Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 4, 1, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 12, 1, v ); - break; - case OP_GEF: - #if DEBUG_VM - if(pass == 1) - printf("%08x GEF\n",instruction); - #endif - makeFloat(opStackDepth-1); - makeFloat(opStackDepth-2); - Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 12, 0, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 4, 0, v ); - break; - - case OP_NEGI: - #if DEBUG_VM - if(pass == 1) - printf("%08x NEGI\n",instruction); - #endif - assertInteger(opStackDepth-1); - InstImm( "subfic", PPC_SUBFIC, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0 ); - opStackLoadInstructionAddr[opStackDepth-1] = 0; - break; - case OP_ADD: - #if DEBUG_VM - if(pass == 1) - printf("%08x ADD\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "add", PPC_ADD, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-2] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_SUB: - #if DEBUG_VM - if(pass == 1) - printf("%08x SUB\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "subf", PPC_SUBF, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-2] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_DIVI: - #if DEBUG_VM - if(pass == 1) - printf("%08x DIVI\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "divw", PPC_DIVW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_DIVU: - #if DEBUG_VM - if(pass == 1) - printf("%08x DIVU\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "divwu", PPC_DIVWU, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_MODI: - #if DEBUG_VM - if(pass == 1) - printf("%08x MODI\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "divw", PPC_DIVW, R_EA, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - Inst( "mullw", PPC_MULLW, R_EA, opStackIntRegisters[opStackDepth-1], R_EA ); - Inst( "subf", PPC_SUBF, opStackIntRegisters[opStackDepth-2], R_EA, opStackIntRegisters[opStackDepth-2] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_MODU: - #if DEBUG_VM - if(pass == 1) - printf("%08x MODU\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "divwu", PPC_DIVWU, R_EA, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - Inst( "mullw", PPC_MULLW, R_EA, opStackIntRegisters[opStackDepth-1], R_EA ); - Inst( "subf", PPC_SUBF, opStackIntRegisters[opStackDepth-2], R_EA, opStackIntRegisters[opStackDepth-2] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_MULI: - case OP_MULU: - #if DEBUG_VM - if(pass == 1) - printf("%08x MULI\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "mullw", PPC_MULLW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-2] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_BAND: - #if DEBUG_VM - if(pass == 1) - printf("%08x BAND\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "and", PPC_AND, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_BOR: - #if DEBUG_VM - if(pass == 1) - printf("%08x BOR\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "or", PPC_OR, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_BXOR: - #if DEBUG_VM - if(pass == 1) - printf("%08x BXOR\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "xor", PPC_XOR, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_BCOM: - #if DEBUG_VM - if(pass == 1) - printf("%08x BCOM\n",instruction); - #endif - assertInteger(opStackDepth-1); - Inst( "nor", PPC_NOR, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1] ); - opStackLoadInstructionAddr[opStackDepth-1] = 0; - break; - case OP_LSH: - #if DEBUG_VM - if(pass == 1) - printf("%08x LSH\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "slw", PPC_SLW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_RSHI: - #if DEBUG_VM - if(pass == 1) - printf("%08x RSHI\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "sraw", PPC_SRAW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_RSHU: - #if DEBUG_VM - if(pass == 1) - printf("%08x RSHU\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "srw", PPC_SRW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - - case OP_NEGF: - #if DEBUG_VM - if(pass == 1) - printf("%08x NEGF\n",instruction); - #endif - makeFloat(opStackDepth-1); - Inst( "fneg", PPC_FNEG, opStackFloatRegisters[opStackDepth-1], 0, opStackFloatRegisters[opStackDepth-1] ); - opStackLoadInstructionAddr[opStackDepth-1] = 0; - break; - case OP_ADDF: - #if DEBUG_VM - if(pass == 1) - printf("%08x ADDF\n",instruction); - #endif - makeFloat(opStackDepth-1); - makeFloat(opStackDepth-2); - Inst( "fadds", PPC_FADDS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_SUBF: - #if DEBUG_VM - if(pass == 1) - printf("%08x SUBF\n",instruction); - #endif - makeFloat(opStackDepth-1); - makeFloat(opStackDepth-2); - Inst( "fsubs", PPC_FSUBS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_DIVF: - #if DEBUG_VM - if(pass == 1) - printf("%08x DIVF\n",instruction); - #endif - makeFloat(opStackDepth-1); - makeFloat(opStackDepth-2); - Inst( "fdivs", PPC_FDIVS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_MULF: - #if DEBUG_VM - if(pass == 1) - printf("%08x MULF\n",instruction); - #endif - makeFloat(opStackDepth-1); - makeFloat(opStackDepth-2); - Inst4( "fmuls", PPC_FMULS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], 0, opStackFloatRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - - case OP_CVIF: - #if DEBUG_VM - if(pass == 1) - printf("%08x CVIF\n",instruction); - #endif - assertInteger(opStackDepth-1); - //makeInteger(opStackDepth-1); - v = (int)&itofConvert; - InstImmU( "addis", PPC_ADDIS, R_EA, 0, (v >> 16)&0xffff ); - InstImmU( "ori", PPC_ORI, R_EA, R_EA, v & 0xffff ); - InstImmU( "xoris", PPC_XORIS, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0x8000 ); - InstImm( "stw", PPC_STW, opStackIntRegisters[opStackDepth-1], R_EA, 12 ); - InstImm( "lfd", PPC_LFD, opStackFloatRegisters[opStackDepth-1], R_EA, 0 ); - Inst( "ori", PPC_ORI, 0, 0, 0); - Inst( "ori", PPC_ORI, 0, 0, 0); - Inst( "ori", PPC_ORI, 0, 0, 0); - InstImm( "lfd", PPC_LFD, 13, R_EA, 8 ); - Inst( "fsub", PPC_FSUB, opStackFloatRegisters[opStackDepth-1], 13, opStackFloatRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 2; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - // Inst( PPC_FRSP, R_TOP, 0, R_TOP ); - break; - case OP_CVFI: - #if DEBUG_VM - if(pass == 1) - printf("%08x CVFI\n",instruction); - #endif - makeFloat(opStackDepth-1); - - InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, opStackDepth*4); - - Inst( "fctiwz", PPC_FCTIWZ, opStackFloatRegisters[opStackDepth-1], 0, opStackFloatRegisters[opStackDepth-1] ); - Inst( "stfiwx", PPC_STFIWX, opStackFloatRegisters[opStackDepth-1], 0, R_OPSTACK ); // save value to opstack (dummy area now) - Inst( "ori", PPC_ORI, 0, 0, 0); - Inst( "ori", PPC_ORI, 0, 0, 0); - Inst( "ori", PPC_ORI, 0, 0, 0); - Inst( "ori", PPC_ORI, 0, 0, 0); - InstImm( "lwz", PPC_LWZ, opStackIntRegisters[opStackDepth-1], R_OPSTACK, 0 ); - - InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, -opStackDepth*4); - - opStackRegType[opStackDepth-1] = 1; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - break; - case OP_SEX8: - #if DEBUG_VM - if(pass == 1) - printf("%08x SEX8\n",instruction); - #endif - assertInteger(opStackDepth-1); - Inst( "extsb", PPC_EXTSB, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0 ); - opStackLoadInstructionAddr[opStackDepth-1] = 0; - break; - case OP_SEX16: - #if DEBUG_VM - if(pass == 1) - printf("%08x SEX16\n",instruction); - #endif - assertInteger(opStackDepth-1); - Inst( "extsh", PPC_EXTSH, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0 ); - opStackLoadInstructionAddr[opStackDepth-1] = 0; - break; - - case OP_BLOCK_COPY: - v = Constant4() >> 2; - #if DEBUG_VM - if(pass == 1) - printf("%08x BLOCK_COPY\t%08lx\n",instruction,v<<2); - #endif - assert(opStackDepth >= 2); - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - InstImmU( "addi", PPC_ADDI, R_EA, 0, v ); // count - // FIXME: range check - Inst( "mtctr", PPC_MTSPR, R_EA, 9, 0 ); // move to count register - - Inst( "add", PPC_ADD, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE ); - InstImm( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], -4 ); - Inst( "add", PPC_ADD, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], R_MEMBASE ); - InstImm( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], -4 ); - - InstImm( "lwzu", PPC_LWZU, R_EA, opStackIntRegisters[opStackDepth-1], 4 ); // source - InstImm( "stwu", PPC_STWU, R_EA, opStackIntRegisters[opStackDepth-2], 4 ); // dest - Inst( "b", PPC_BC | 0xfff8 , 16, 0, 0 ); // loop - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - break; - - case OP_JUMP: - #if DEBUG_VM - if(pass == 1) - printf("%08x JUMP\n",instruction); - #endif - assert(opStackDepth == 1); - assertInteger(opStackDepth-1); - - Inst( "rlwinm", PPC_RLWINM | ( 29 << 1 ), opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 2 ); - // FIXME: range check - Inst( "lwzx", PPC_LWZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_INSTRUCTIONS ); - Inst( "mtctr", PPC_MTSPR, opStackIntRegisters[opStackDepth-1], 9, 0 ); // move to count register - Inst( "bctr", PPC_BCCTR, 20, 0, 0 ); // jump to the count register - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - default: - Com_Error( ERR_DROP, "VM_CompilePPC: bad opcode %i at instruction %i, offset %i", op, instruction, pc ); - } - pop0 = pop1; - pop1 = op; - assert(opStackDepth >= 0); - assert(opStackDepth < OP_STACK_MAX_DEPTH); - - //printf("%4d\t%s\n",opStackDepth,opnames[op]); - } - - Com_Printf( "VM file %s pass %d compiled to %i bytes of code\n", vm->name, (pass+1), compiledOfs*4 ); - - if ( pass == 0 ) { - // copy to an exact size buffer on the hunk - vm->codeLength = compiledOfs * 4; - vm->codeBase = Hunk_Alloc( vm->codeLength, h_low ); - Com_Memcpy( vm->codeBase, buf, vm->codeLength ); - - //printf("codeBase: %p\n",vm->codeBase); - - Z_Free( buf ); - - // offset all the instruction pointers for the new location - for ( i = 0 ; i < header->instructionCount ; i++ ) { - vm->instructionPointers[i] += (int)vm->codeBase; - //printf("%08x %08lx\n",i,vm->instructionPointers[i]); - } - - // go back over it in place now to fixup reletive jump targets - buf = (unsigned *)vm->codeBase; - } else if ( pass == 1 ) { - #ifdef MACOS_X - // On Mac OS X, the following library routine clears the instruction cache for generated code - MakeDataExecutable(vm->codeBase, vm->codeLength); - #else - #warning Need to clear the instruction cache for generated code - #endif - } - } - if(0) - { - char buf[256]; - printf("wait..\n"); - gets(buf); - } - Z_Free( jused ); -} - -/* -============== -VM_CallCompiled - -This function is called directly by the generated code -============== -*/ -int VM_CallCompiled( vm_t *vm, int *args ) { - int stack[1024]; - int programStack; - int stackOnEntry; - byte *image; - - currentVM = vm; - - //printf("VM_CallCompiled: %p %08lx %08lx %08lx\n", - // vm, args[0],args[1],args[2]); - - // interpret the code - vm->currentlyInterpreting = qtrue; - - // we might be called recursively, so this might not be the very top - programStack = vm->programStack; - stackOnEntry = programStack; - image = vm->dataBase; - - // set up the stack frame - programStack -= 48; - - *(int *)&image[ programStack + 44] = args[9]; - *(int *)&image[ programStack + 40] = args[8]; - *(int *)&image[ programStack + 36] = args[7]; - *(int *)&image[ programStack + 32] = args[6]; - *(int *)&image[ programStack + 28] = args[5]; - *(int *)&image[ programStack + 24] = args[4]; - *(int *)&image[ programStack + 20] = args[3]; - *(int *)&image[ programStack + 16] = args[2]; - *(int *)&image[ programStack + 12] = args[1]; - *(int *)&image[ programStack + 8 ] = args[0]; - *(int *)&image[ programStack + 4 ] = 0; // return stack - *(int *)&image[ programStack ] = -1; // will terminate the loop on return - - // Cheesy... manually save registers used by VM call... - // off we go into generated code... - // the PPC calling standard says the parms will all go into R3 - R11, so - // no special asm code is needed here -#ifdef __GNUC__ - ((void(*)(int, int, int, int, int, int, int, int))(vm->codeBase))( - programStack, (int)&stack, - (int)image, vm->dataMask, (int)&AsmCall, - (int)vm->instructionPointers, vm->instructionPointersLength, - (int)vm ); -#else - ((void(*)(int, int, int, int, int, int, int, int))(vm->codeBase))( - programStack, (int)&stack, - (int)image, vm->dataMask, *(int *)&AsmCall /* skip function pointer header */, - (int)vm->instructionPointers, vm->instructionPointersLength, - (int)vm ); -#endif - vm->programStack = stackOnEntry; - - vm->currentlyInterpreting = qfalse; - - return stack[1]; -} - - -/* -================== -AsmCall - -Put this at end of file because gcc messes up debug line numbers -================== -*/ -#ifdef __GNUC__ - -void AsmCall( void ) { -asm ( - // pop off the destination instruction -" lwz r12,0(r4) \n" // RG_TOP, 0(RG_OPSTACK) -" addi r4,r4,-4 \n" // RG_OPSTACK, RG_OPSTACK, -4 \n" - - // see if it is a system trap -" cmpwi r12,0 \n" // RG_TOP, 0 \n" -" bc 12,0, systemTrap \n" - - // calling another VM function, so lookup in instructionPointers -" slwi r12,r12,2 \n" // RG_TOP,RG_TOP,2 - // FIXME: range check -" lwzx r12, r8, r12 \n" // RG_TOP, RG_INSTRUCTIONS(RG_TOP) -" mtctr r12 \n" // RG_TOP -); - -#if defined(MACOS_X) && defined(__OPTIMIZE__) - // On Mac OS X, gcc doesn't push a frame when we are optimized, so trying to tear it down results in grave disorder. -//#warning Mac OS X optimization on, not popping GCC AsmCall frame -#else - // Mac OS X Server and unoptimized compiles include a GCC AsmCall frame - asm ( -" lwz r1,0(r1) \n" // pop off the GCC AsmCall frame -" lmw r30,-8(r1) \n" -); -#endif - -asm ( -" bcctr 20,0 \n" // when it hits a leave, it will branch to the current link register - - // calling a system trap -"systemTrap: \n" - // convert to positive system call number -" subfic r12,r12,-1 \n" - - // save all our registers, including the current link register -" mflr r13 \n" // RG_SECOND // copy off our link register -" addi r1,r1,-92 \n" // required 24 byets of linkage, 32 bytes of parameter, plus our saves -" stw r3,56(r1) \n" // RG_STACK, -36(REAL_STACK) -" stw r4,60(r1) \n" // RG_OPSTACK, 4(RG_REAL_STACK) -" stw r5,64(r1) \n" // RG_MEMBASE, 8(RG_REAL_STACK) -" stw r6,68(r1) \n" // RG_MEMMASK, 12(RG_REAL_STACK) -" stw r7,72(r1) \n" // RG_ASMCALL, 16(RG_REAL_STACK) -" stw r8,76(r1) \n" // RG_INSTRUCTIONS, 20(RG_REAL_STACK) -" stw r9,80(r1) \n" // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK) -" stw r10,84(r1) \n" // RG_VM, 28(RG_REAL_STACK) -" stw r13,88(r1) \n" // RG_SECOND, 32(RG_REAL_STACK) // link register - - // save the vm stack position to allow recursive VM entry -" addi r13,r3,-4 \n" // RG_TOP, RG_STACK, -4 -" stw r13,0(r10) \n" //RG_TOP, VM_OFFSET_PROGRAM_STACK(RG_VM) - - // save the system call number as the 0th parameter -" add r3,r3,r5 \n" // r3, RG_STACK, RG_MEMBASE // r3 is the first parameter to vm->systemCalls -" stwu r12,4(r3) \n" // RG_TOP, 4(r3) - - // make the system call with the address of all the VM parms as a parameter - // vm->systemCalls( &parms ) -" lwz r12,4(r10) \n" // RG_TOP, VM_OFFSET_SYSTEM_CALL(RG_VM) -" mtctr r12 \n" // RG_TOP -" bcctrl 20,0 \n" -" mr r12,r3 \n" // RG_TOP, r3 - - // pop our saved registers -" lwz r3,56(r1) \n" // RG_STACK, 0(RG_REAL_STACK) -" lwz r4,60(r1) \n" // RG_OPSTACK, 4(RG_REAL_STACK) -" lwz r5,64(r1) \n" // RG_MEMBASE, 8(RG_REAL_STACK) -" lwz r6,68(r1) \n" // RG_MEMMASK, 12(RG_REAL_STACK) -" lwz r7,72(r1) \n" // RG_ASMCALL, 16(RG_REAL_STACK) -" lwz r8,76(r1) \n" // RG_INSTRUCTIONS, 20(RG_REAL_STACK) -" lwz r9,80(r1) \n" // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK) -" lwz r10,84(r1) \n" // RG_VM, 28(RG_REAL_STACK) -" lwz r13,88(r1) \n" // RG_SECOND, 32(RG_REAL_STACK) -" addi r1,r1,92 \n" // RG_REAL_STACK, RG_REAL_STACK, 36 - - // restore the old link register -" mtlr r13 \n" // RG_SECOND - - // save off the return value -" stwu r12,4(r4) \n" // RG_TOP, 0(RG_OPSTACK) - - // GCC adds its own prolog / epliog code - ); -} -#else - -// codewarrior version - -void asm AsmCall( void ) { - - // pop off the destination instruction - - lwz r12,0(r4) // RG_TOP, 0(RG_OPSTACK) - - addi r4,r4,-4 // RG_OPSTACK, RG_OPSTACK, -4 - - - - // see if it is a system trap - - cmpwi r12,0 // RG_TOP, 0 - - bc 12,0, systemTrap - - - - // calling another VM function, so lookup in instructionPointers - - slwi r12,r12,2 // RG_TOP,RG_TOP,2 - - // FIXME: range check - - lwzx r12, r8, r12 // RG_TOP, RG_INSTRUCTIONS(RG_TOP) - - mtctr r12 // RG_TOP - - - - bcctr 20,0 // when it hits a leave, it will branch to the current link register - - - - // calling a system trap - -systemTrap: - - // convert to positive system call number - - subfic r12,r12,-1 - - - - // save all our registers, including the current link register - - mflr r13 // RG_SECOND // copy off our link register - - addi r1,r1,-92 // required 24 byets of linkage, 32 bytes of parameter, plus our saves - - stw r3,56(r1) // RG_STACK, -36(REAL_STACK) - - stw r4,60(r1) // RG_OPSTACK, 4(RG_REAL_STACK) - - stw r5,64(r1) // RG_MEMBASE, 8(RG_REAL_STACK) - - stw r6,68(r1) // RG_MEMMASK, 12(RG_REAL_STACK) - - stw r7,72(r1) // RG_ASMCALL, 16(RG_REAL_STACK) - - stw r8,76(r1) // RG_INSTRUCTIONS, 20(RG_REAL_STACK) - - stw r9,80(r1) // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK) - - stw r10,84(r1) // RG_VM, 28(RG_REAL_STACK) - - stw r13,88(r1) // RG_SECOND, 32(RG_REAL_STACK) // link register - - - - // save the vm stack position to allow recursive VM entry - - addi r13,r3,-4 // RG_TOP, RG_STACK, -4 - - stw r13,0(r10) //RG_TOP, VM_OFFSET_PROGRAM_STACK(RG_VM) - - - - // save the system call number as the 0th parameter - - add r3,r3,r5 // r3, RG_STACK, RG_MEMBASE // r3 is the first parameter to vm->systemCalls - - stwu r12,4(r3) // RG_TOP, 4(r3) - - - - // make the system call with the address of all the VM parms as a parameter - - // vm->systemCalls( &parms ) - - lwz r12,4(r10) // RG_TOP, VM_OFFSET_SYSTEM_CALL(RG_VM) - - - - // perform macos cross fragment fixup crap - - lwz r9,0(r12) - - stw r2,52(r1) // save old TOC - - lwz r2,4(r12) - - - - mtctr r9 // RG_TOP - - bcctrl 20,0 - - - - lwz r2,52(r1) // restore TOC - - - - mr r12,r3 // RG_TOP, r3 - - - - // pop our saved registers - - lwz r3,56(r1) // RG_STACK, 0(RG_REAL_STACK) - - lwz r4,60(r1) // RG_OPSTACK, 4(RG_REAL_STACK) - - lwz r5,64(r1) // RG_MEMBASE, 8(RG_REAL_STACK) - - lwz r6,68(r1) // RG_MEMMASK, 12(RG_REAL_STACK) - - lwz r7,72(r1) // RG_ASMCALL, 16(RG_REAL_STACK) - - lwz r8,76(r1) // RG_INSTRUCTIONS, 20(RG_REAL_STACK) - - lwz r9,80(r1) // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK) - - lwz r10,84(r1) // RG_VM, 28(RG_REAL_STACK) - - lwz r13,88(r1) // RG_SECOND, 32(RG_REAL_STACK) - - addi r1,r1,92 // RG_REAL_STACK, RG_REAL_STACK, 36 - - - - // restore the old link register - - mtlr r13 // RG_SECOND - - - - // save off the return value - - stwu r12,4(r4) // RG_TOP, 0(RG_OPSTACK) - - - - blr - -} - - - - -#endif diff --git a/src/qcommon/vm_x86_64.c b/src/qcommon/vm_x86_64.c index 9fde6e75..e8e827e5 100644 --- a/src/qcommon/vm_x86_64.c +++ b/src/qcommon/vm_x86_64.c @@ -43,15 +43,19 @@ static FILE* qdasmout; static void VM_Destroy_Compiled(vm_t* self); /* + + |=====================| + ^ dataMask ^- programStack rdi + | + +- r8 eax scratch ebx scratch ecx scratch (required for shifts) edx scratch (required for divisions) - rsi stack pointer - rdi program frame pointer - r8 pointer to begin of real stack memory - r9 return address to real program + rsi stack pointer (opStack) + rdi program frame pointer (programStack) + r8 pointer data (vm->dataBase) r10 start of generated code */ @@ -266,6 +270,15 @@ static unsigned char op_argsize[256] = #if 1 #define RANGECHECK(reg) \ emit("andl $0x%x, %%" #reg, vm->dataMask); +#elif 0 +#define RANGECHECK(reg) \ + emit("pushl %%" #reg); \ + emit("andl $0x%x, %%" #reg, ~vm->dataMask); \ + emit("jz rangecheck_ok_i_%08x", instruction); \ + emit("int3"); \ + emit("rangecheck_ok_i_%08x:", instruction); \ + emit("popl %%" #reg); \ + emit("andl $0x%x, %%" #reg, vm->dataMask); #else #define RANGECHECK(reg) #endif @@ -412,10 +425,17 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { Com_Printf("compiling %s\n", vm->name); +#ifdef DEBUG_VM + snprintf(fn_s, sizeof(fn_s), "%.63s.s", vm->name); + snprintf(fn_o, sizeof(fn_o), "%.63s.o", vm->name); + fd_s = open(fn_s, O_CREAT|O_WRONLY, 0644); + fd_o = open(fn_o, O_CREAT|O_WRONLY, 0644); +#else snprintf(fn_s, sizeof(fn_s), "/tmp/%.63s.s_XXXXXX", vm->name); snprintf(fn_o, sizeof(fn_o), "/tmp/%.63s.o_XXXXXX", vm->name); fd_s = mkstemp(fn_s); fd_o = mkstemp(fn_o); +#endif if(fd_s == -1 || fd_o == -1) { if(fd_s != -1) close(fd_s); @@ -451,8 +471,6 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { emit("or %%r8, %%r8"); // check whether to set up instruction pointers emit("jnz main"); emit("jmp setupinstructionpointers"); - emit("exit:"); - emit("jmp *%%r9"); emit("main:"); @@ -502,16 +520,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { break; case OP_LEAVE: emit("addl $%d, %%edi", iarg); // get rid of stack frame - RANGECHECK(edi); - emit("movl 0(%%r8, %%rdi, 1), %%eax"); // get return address - emit("movq $%lu, %%rbx", (unsigned long)vm->instructionPointers); - emit("cmp $-1, %%eax"); - emit("je jumptoexit%d", instruction); - emit("movl (%%rbx, %%rax, 4), %%eax"); // load new relative jump address - emit("addq %%r10, %%rax"); - emit("jmp *%%rax"); - emit("jumptoexit%d:", instruction); - emit("jmp exit"); + emit("ret"); break; case OP_CALL: emit("movl 0(%%rsi), %%eax"); // get instr from stack @@ -522,7 +531,8 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { emit("movq $%lu, %%rbx", (unsigned long)vm->instructionPointers); emit("movl (%%rbx, %%rax, 4), %%eax"); // load new relative jump address emit("addq %%r10, %%rax"); - emit("jmp *%%rax"); + emit("callq *%%rax"); + emit("jmp i_%08x", instruction+1); emit("callSyscall%d:", instruction); // emit("fnsave 4(%%rsi)"); emit("push %%rsi"); @@ -530,14 +540,19 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { emit("push %%r8"); emit("push %%r9"); emit("push %%r10"); - emit("push %%r10"); // align! + emit("movq %%rsp, %%rbx"); // we need to align the stack pointer + emit("subq $8, %%rbx"); // | + emit("andq $127, %%rbx"); // | + emit("subq %%rbx, %%rsp"); // <-+ + emit("push %%rbx"); emit("negl %%eax"); // convert to actual number emit("decl %%eax"); // first argument already in rdi emit("movq %%rax, %%rsi"); // second argument in rsi emit("movq $%lu, %%rax", (unsigned long)callAsmCall); emit("callq *%%rax"); - emit("pop %%r10"); + emit("pop %%rbx"); + emit("addq %%rbx, %%rsp"); emit("pop %%r10"); emit("pop %%r9"); emit("pop %%r8"); @@ -545,7 +560,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { emit("pop %%rsi"); // emit("frstor 4(%%rsi)"); emit("addq $4, %%rsi"); - emit("movl %%eax, (%%rsi)"); + emit("movl %%eax, (%%rsi)"); // store return value break; case OP_PUSH: emit("addq $4, %%rsi"); @@ -634,21 +649,21 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { XJ("jb"); break; case OP_LOAD1: - emit("movl 0(%%rsi), %%eax"); // get pointer from stack + emit("movl 0(%%rsi), %%eax"); // get value from stack RANGECHECK(eax); emit("movb 0(%%r8, %%rax, 1), %%al"); // deref into eax emit("andq $255, %%rax"); emit("movl %%eax, 0(%%rsi)"); // store on stack break; case OP_LOAD2: - emit("movl 0(%%rsi), %%eax"); // get pointer from stack + emit("movl 0(%%rsi), %%eax"); // get value from stack RANGECHECK(eax); - emit("movw 0(%%r8, %%rax, 1), %%rax"); // deref into eax + emit("movw 0(%%r8, %%rax, 1), %%ax"); // deref into eax emit("movl %%eax, 0(%%rsi)"); // store on stack break; case OP_LOAD4: - emit("movl 0(%%rsi), %%eax"); // get pointer from stack - RANGECHECK(eax); + emit("movl 0(%%rsi), %%eax"); // get value from stack + RANGECHECK(eax); // not a pointer!? emit("movl 0(%%r8, %%rax, 1), %%eax"); // deref into eax emit("movl %%eax, 0(%%rsi)"); // store on stack break; @@ -664,7 +679,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { emit("movl 0(%%rsi), %%eax"); // get value from stack emit("movl -4(%%rsi), %%ebx"); // get pointer from stack RANGECHECK(ebx); - emit("movw %%rax, 0(%%r8, %%rbx, 1)"); // store in memory + emit("movw %%ax, 0(%%r8, %%rbx, 1)"); // store in memory emit("subq $8, %%rsi"); break; case OP_STORE4: @@ -703,14 +718,14 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { break; case OP_SEX8: - emit("movw 0(%%rsi), %%rax"); + emit("movw 0(%%rsi), %%ax"); emit("andq $255, %%rax"); emit("cbw"); emit("cwde"); emit("movl %%eax, 0(%%rsi)"); break; case OP_SEX16: - emit("movw 0(%%rsi), %%rax"); + emit("movw 0(%%rsi), %%ax"); emit("cwde"); emit("movl %%eax, 0(%%rsi)"); break; @@ -741,14 +756,15 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { emit("subq $4, %%rsi"); emit("movl 0(%%rsi), %%eax"); emit("xorl %%edx, %%edx"); - emit("divl 4(%%rsi)"); + emit("cdq"); + emit("idivl 4(%%rsi)"); emit("movl %%edx, 0(%%rsi)"); break; case OP_MODU: emit("subq $4, %%rsi"); emit("movl 0(%%rsi), %%eax"); emit("xorl %%edx, %%edx"); - emit("idivl 4(%%rsi)"); + emit("divl 4(%%rsi)"); emit("movl %%edx, 0(%%rsi)"); break; case OP_MULI: @@ -847,7 +863,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { { emit("movl $i_%08x-start, %d(%%rax)", instruction, instruction*4); } - emit("jmp exit"); + emit("ret"); emit("debugger:"); if(1); @@ -883,28 +899,30 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { // call code with r8 set to zero to set up instruction pointers __asm__ __volatile__ ( " xorq %%r8,%%r8 \r\n" \ - " movq $doneinit,%%r9 \r\n" \ " movq %0,%%r10 \r\n" \ - " jmp *%%r10 \r\n" \ - "doneinit: \r\n" \ + " callq *%%r10 \r\n" \ : : "m" (entryPoint) - : "%r8", "%r9", "%r10", "%rax" + : "%r8", "%r10", "%rax" ); #ifdef DEBUG_VM fflush(qdasmout); + fclose(qdasmout); #endif Com_Printf( "VM file %s compiled to %i bytes of code (%p - %p)\n", vm->name, vm->codeLength, vm->codeBase, vm->codeBase+vm->codeLength ); out: close(fd_o); + +#ifndef DEBUG_VM if(!com_developer->integer) { unlink(fn_o); unlink(fn_s); } +#endif } @@ -978,16 +996,16 @@ int VM_CallCompiled( vm_t *vm, int *args ) { __asm__ __volatile__ ( " movq %5,%%rsi \r\n" \ " movl %4,%%edi \r\n" \ - " movq $done,%%r9 \r\n" \ " movq %2,%%r10 \r\n" \ " movq %3,%%r8 \r\n" \ - " jmp *%%r10 \r\n" \ - "done: \r\n" \ + " subq $24, %%rsp # fix alignment as call pushes one value \r\n" \ + " callq *%%r10 \r\n" \ + " addq $24, %%rsp \r\n" \ " movl %%edi, %0 \r\n" \ " movq %%rsi, %1 \r\n" \ : "=m" (programStack), "=m" (opStack) : "m" (entryPoint), "m" (vm->dataBase), "m" (programStack), "m" (opStack) - : "%rsi", "%rdi", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r15", "%xmm0" + : "%rsi", "%rdi", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r10", "%r15", "%xmm0" ); if ( opStack != &stack[1] ) { |