📄 vm_ppc_new.c
字号:
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -