forked from dolphin-emu/dolphin
		
	enabled nr in jit after getting skid_au's help in writing the inscrease_addr_reg. ector can you please take a look and see if the loop code makes sense? it seems no one it really sure how loops suppose to work in jit git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5301 8ced0084-cf51-0410-be5f-012b33b47a6e
		
			
				
	
	
		
			232 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			232 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// Copyright (C) 2010 Dolphin Project.
 | 
						|
 | 
						|
// This program is free software: you can redistribute it and/or modify
 | 
						|
// it under the terms of the GNU General Public License as published by
 | 
						|
// the Free Software Foundation, version 2.0.
 | 
						|
 | 
						|
// This program is distributed in the hope that it will be useful,
 | 
						|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
// GNU General Public License 2.0 for more details.
 | 
						|
 | 
						|
// A copy of the GPL 2.0 should have been included with the program.
 | 
						|
// If not, see http://www.gnu.org/licenses/
 | 
						|
 | 
						|
// Official SVN repository and contact information can be found at
 | 
						|
// http://code.google.com/p/dolphin-emu/
 | 
						|
 | 
						|
#include <cstring>
 | 
						|
 | 
						|
#include "DSPEmitter.h"
 | 
						|
#include "DSPMemoryMap.h"
 | 
						|
#include "DSPCore.h"
 | 
						|
#include "DSPInterpreter.h"
 | 
						|
#include "DSPAnalyzer.h"
 | 
						|
#include "x64Emitter.h"
 | 
						|
#include "ABI.h"
 | 
						|
 | 
						|
#define BLOCK_SIZE 250
 | 
						|
 | 
						|
using namespace Gen;
 | 
						|
 | 
						|
DSPEmitter::DSPEmitter()
 | 
						|
{
 | 
						|
	m_compiledCode = NULL;
 | 
						|
 | 
						|
	AllocCodeSpace(COMPILED_CODE_SIZE);
 | 
						|
 | 
						|
	blocks = new CompiledCode[MAX_BLOCKS];
 | 
						|
	endBlock = new bool[MAX_BLOCKS];
 | 
						|
 | 
						|
	for(int i = 0x0000; i < MAX_BLOCKS; i++)
 | 
						|
	{
 | 
						|
		blocks[i] = CompileCurrent;
 | 
						|
		blockSize[i] = 0;
 | 
						|
		endBlock[i] = false;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
DSPEmitter::~DSPEmitter() 
 | 
						|
{
 | 
						|
	delete[] blocks;
 | 
						|
	delete[] endBlock;
 | 
						|
	FreeCodeSpace();
 | 
						|
}
 | 
						|
 | 
						|
void DSPEmitter::ClearIRAM() {
 | 
						|
	// TODO: Does not clear codespace
 | 
						|
	for(int i = 0x0000; i < 0x1000; i++)
 | 
						|
	{
 | 
						|
		blocks[i] = CompileCurrent;
 | 
						|
		blockSize[i] = 0;
 | 
						|
		endBlock[i] = false;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void DSPEmitter::WriteCallInterpreter(UDSPInstruction inst)
 | 
						|
{
 | 
						|
	const DSPOPCTemplate *tinst = GetOpTemplate(inst);
 | 
						|
 | 
						|
	// Call extended
 | 
						|
	if (tinst->extended) {
 | 
						|
		if ((inst >> 12) == 0x3) {
 | 
						|
			if (! extOpTable[inst & 0x7F]->jitFunc) {
 | 
						|
				ABI_CallFunctionC16((void*)extOpTable[inst & 0x7F]->intFunc, inst);
 | 
						|
			} else {
 | 
						|
				(this->*extOpTable[inst & 0x7F]->jitFunc)(inst);
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			if (!extOpTable[inst & 0xFF]->jitFunc) {
 | 
						|
				ABI_CallFunctionC16((void*)extOpTable[inst & 0xFF]->intFunc, inst);
 | 
						|
			} else {
 | 
						|
				(this->*extOpTable[inst & 0xFF]->jitFunc)(inst);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	
 | 
						|
	// Main instruction
 | 
						|
	if (!opTable[inst]->jitFunc)
 | 
						|
		ABI_CallFunctionC16((void*)opTable[inst]->intFunc, inst);
 | 
						|
	else
 | 
						|
		(this->*opTable[inst]->jitFunc)(inst);
 | 
						|
 | 
						|
	// Backlog
 | 
						|
	// TODO if for jit
 | 
						|
	if (tinst->extended) {
 | 
						|
		ABI_CallFunction((void*)applyWriteBackLog);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void DSPEmitter::unknown_instruction(UDSPInstruction inst)
 | 
						|
{
 | 
						|
	PanicAlert("unknown_instruction %04x - Fix me ;)", inst);
 | 
						|
}
 | 
						|
 | 
						|
void DSPEmitter::Default(UDSPInstruction _inst)
 | 
						|
{
 | 
						|
	WriteCallInterpreter(_inst);
 | 
						|
}
 | 
						|
 | 
						|
const u8 *DSPEmitter::Compile(int start_addr) {
 | 
						|
	AlignCode16();
 | 
						|
	const u8 *entryPoint = GetCodePtr();
 | 
						|
	//	ABI_PushAllCalleeSavedRegsAndAdjustStack();
 | 
						|
 | 
						|
	int addr = start_addr;
 | 
						|
 | 
						|
	while (addr < start_addr + BLOCK_SIZE)
 | 
						|
	{
 | 
						|
		UDSPInstruction inst = dsp_imem_read(addr);
 | 
						|
		const DSPOPCTemplate *opcode = GetOpTemplate(inst);
 | 
						|
 | 
						|
		// Check for interrupts and exceptions
 | 
						|
		TEST(8, M(&g_dsp.exceptions), Imm8(0xff));
 | 
						|
		FixupBranch skipCheck = J_CC(CC_Z);
 | 
						|
		
 | 
						|
		ABI_CallFunction((void *)&DSPCore_CheckExceptions);
 | 
						|
		
 | 
						|
		MOV(32, R(EAX), M(&g_dsp.exception_in_progress));
 | 
						|
		CMP(32, R(EAX), Imm32(0));
 | 
						|
		FixupBranch noExceptionOccurred = J_CC(CC_L);
 | 
						|
		
 | 
						|
		//	ABI_CallFunction((void *)DSPInterpreter::HandleLoop);
 | 
						|
		//	ABI_PopAllCalleeSavedRegsAndAdjustStack();
 | 
						|
		RET();
 | 
						|
		
 | 
						|
		SetJumpTarget(skipCheck);
 | 
						|
		SetJumpTarget(noExceptionOccurred);
 | 
						|
		
 | 
						|
		// Increment PC
 | 
						|
		ADD(16, M(&(g_dsp.pc)), Imm16(1));
 | 
						|
 | 
						|
		WriteCallInterpreter(inst);
 | 
						|
				
 | 
						|
		blockSize[start_addr]++;
 | 
						|
 | 
						|
		// Handle loop condition.  Change to TEST
 | 
						|
		MOVZX(32, 16, EAX, M(&(g_dsp.r[DSP_REG_ST2])));
 | 
						|
		CMP(32, R(EAX), Imm32(0));
 | 
						|
		FixupBranch rLoopAddressExit = J_CC(CC_LE);
 | 
						|
		
 | 
						|
		MOVZX(32, 16, EAX, M(&(g_dsp.r[DSP_REG_ST3])));
 | 
						|
		CMP(32, R(EAX), Imm32(0));
 | 
						|
		FixupBranch rLoopCounterExit = J_CC(CC_LE);
 | 
						|
 | 
						|
		// These functions branch and therefore only need to be called in the
 | 
						|
		// end of each block and in this order
 | 
						|
	    ABI_CallFunction((void *)&DSPInterpreter::HandleLoop);
 | 
						|
		//	ABI_PopAllCalleeSavedRegsAndAdjustStack();
 | 
						|
		RET();
 | 
						|
 | 
						|
		SetJumpTarget(rLoopAddressExit);
 | 
						|
		SetJumpTarget(rLoopCounterExit);
 | 
						|
 | 
						|
		// End the block where the loop ends
 | 
						|
		if ((inst & 0xffe0) == 0x0060 || (inst & 0xff00) == 0x1100) {
 | 
						|
			// BLOOP, BLOOPI
 | 
						|
			endBlock[dsp_imem_read(addr + 1)] = true;
 | 
						|
		} else if ((inst & 0xffe0) == 0x0040 || (inst & 0xff00) == 0x1000) {
 | 
						|
			// LOOP, LOOPI
 | 
						|
			endBlock[addr + 1] = true;
 | 
						|
		}
 | 
						|
 | 
						|
		if (opcode->branch || endBlock[addr] 
 | 
						|
			|| (DSPAnalyzer::code_flags[addr] & DSPAnalyzer::CODE_IDLE_SKIP)) {
 | 
						|
			break;
 | 
						|
		}
 | 
						|
		addr += opcode->size;
 | 
						|
	}
 | 
						|
 | 
						|
	//	ABI_PopAllCalleeSavedRegsAndAdjustStack();
 | 
						|
	RET();
 | 
						|
 | 
						|
	blocks[start_addr] = (CompiledCode)entryPoint;
 | 
						|
 | 
						|
	return entryPoint;
 | 
						|
}
 | 
						|
 | 
						|
void STACKALIGN DSPEmitter::RunBlock(int cycles)
 | 
						|
{
 | 
						|
	static int idleskip = 0;
 | 
						|
	// Trigger an external interrupt at the start of the cycle
 | 
						|
	u16 block_cycles = 501;
 | 
						|
 | 
						|
	while (!(g_dsp.cr & CR_HALT))
 | 
						|
	{
 | 
						|
		if (block_cycles > 500)
 | 
						|
		{
 | 
						|
			if(g_dsp.cr & CR_EXTERNAL_INT)
 | 
						|
				DSPCore_CheckExternalInterrupt();
 | 
						|
			block_cycles = 0;
 | 
						|
		}
 | 
						|
 | 
						|
		// Compile the block if needed
 | 
						|
		if (blocks[g_dsp.pc] == CompileCurrent)
 | 
						|
		{
 | 
						|
			blockSize[g_dsp.pc] = 0;
 | 
						|
			blocks[g_dsp.pc]();
 | 
						|
		}
 | 
						|
		
 | 
						|
		// Execute the block if we have enough cycles
 | 
						|
		if (cycles > blockSize[g_dsp.pc])
 | 
						|
		{
 | 
						|
			u16 start_addr = g_dsp.pc;
 | 
						|
			if (idleskip % 100 > 95 && (DSPAnalyzer::code_flags[g_dsp.pc] & DSPAnalyzer::CODE_IDLE_SKIP)) {
 | 
						|
				block_cycles = 0;
 | 
						|
			} else
 | 
						|
				blocks[g_dsp.pc]();
 | 
						|
			
 | 
						|
			idleskip++;
 | 
						|
 | 
						|
			if (idleskip % 500 == 0)
 | 
						|
				idleskip = 0;
 | 
						|
 | 
						|
			block_cycles += blockSize[start_addr];
 | 
						|
			cycles -= blockSize[start_addr];		
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |