⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vm_ppc_new.c

📁 quakeIII源码这个不用我多说吧
💻 C
📖 第 1 页 / 共 5 页
字号:
	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 + -