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