📄 vm_ppc_new.c
字号:
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 ltop() {
// if (rtopped == qfalse) {
// InstImm( PPC_LWZ, R_TOP, R_OPSTACK, 0 ); // get value from opstack
// }
}
static void ltopandsecond() {
#if 0
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;
#endif
}
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 makeInteger(int depth)
{
// This should really never be necessary...
assert(opStackRegType[depth] == 1);
//assert(opStackRegType[depth] == 2);
if(opStackRegType[depth] == 2)
{
unsigned instruction;
assert(opStackLoadInstructionAddr[depth]);
printf("patching float load at %p to int load\n",opStackLoadInstructionAddr[depth]);
// Repatch load instruction to use LFS instead of LWZ
instruction = *opStackLoadInstructionAddr[depth];
instruction &= ~PPC_LFSX;
instruction |= PPC_LWZX;
*opStackLoadInstructionAddr[depth] = instruction;
opStackLoadInstructionAddr[depth] = 0;
opStackRegType[depth] = 1;
#if 0
InstImm( "stfs", PPC_STFS, opStackFloatRegisters[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( "lwz", PPC_LWZ, opStackIntRegisters[depth], R_OPSTACK, depth*4+4);
opStackRegType[depth] = 1;
#endif
}
}
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -