📄 vm_ppc.c
字号:
if ( immediate > 0xffff || immediate < 0 ) {
Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range", immediate );
}
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 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;
}
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
#if 0
static void fltop() {
if (rtopped == qfalse) {
InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack
}
}
#endif
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;
}
/*
=================
VM_Compile
=================
*/
void VM_Compile( vm_t *vm, vmHeader_t *header ) {
int op;
int maxLength;
int v;
int i;
// 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++ ) {
rtopped = qfalse;
// translate all instructions
pc = 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:
InstImmU( PPC_ADDI, R_TOP, 0, 0 );
InstImm( PPC_LWZ, R_TOP, R_TOP, 0 ); // *(int *)0 to crash to debugger
rtopped = qfalse;
break;
case OP_ENTER:
InstImm( PPC_ADDI, R_STACK, R_STACK, -Constant4() ); // sub R_STACK, R_STACK, imm
rtopped = qfalse;
break;
case OP_CONST:
v = Constant4();
if (code[pc] == OP_LOAD4 || code[pc] == OP_LOAD2 || code[pc] == OP_LOAD1) {
v &= vm->dataMask;
}
if ( v < 32768 && v >= -32768 ) {
InstImmU( PPC_ADDI, R_TOP, 0, v & 0xffff );
} else {
InstImmU( PPC_ADDIS, R_TOP, 0, (v >> 16)&0xffff );
if ( v & 0xffff ) {
InstImmU( PPC_ORI, R_TOP, R_TOP, 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;
}
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 (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;
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;
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;
break;
case OP_PUSH:
InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, 4 );
rtopped = qfalse;
break;
case OP_POP:
InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
rtopped = qfalse;
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;
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;
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;
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;
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;
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;
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;
break;
case OP_EQ:
ltopandsecond(); // get value from opstack
Inst( PPC_CMP, 0, R_SECOND, R_TOP );
i = Constant4();
jused[i] = 1;
InstImm( 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;
break;
case OP_NE:
ltopandsecond(); // get value from opstack
Inst( PPC_CMP, 0, R_SECOND, R_TOP );
i = Constant4();
jused[i] = 1;
InstImm( 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;
break;
case OP_LTI:
ltopandsecond(); // get value from opstack
Inst( PPC_CMP, 0, R_SECOND, R_TOP );
i = Constant4();
jused[i] = 1;
InstImm( 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;
break;
case OP_LEI:
ltopandsecond(); // get value from opstack
Inst( PPC_CMP, 0, R_SECOND, R_TOP );
i = Constant4();
jused[i] = 1;
InstImm( 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;
break;
case OP_GTI:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -