forked from dolphin-emu/dolphin
		
	functions accidentally added. Fixed the jitted ar register arithmetic. Added a CMakeList.txt for the UnitTests, but did not add the subdirectory to Source/CMakeLists.txt. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6687 8ced0084-cf51-0410-be5f-012b33b47a6e
		
			
				
	
	
		
			311 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			311 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include "DSPJitTester.h"
 | 
						|
 | 
						|
DSPJitTester::DSPJitTester(u16 opcode, u16 opcode_ext, bool verbose, bool only_failed)
 | 
						|
	: be_verbose(verbose), failed_only(only_failed), run_count(0), fail_count(0)
 | 
						|
{
 | 
						|
	instruction = opcode | opcode_ext;
 | 
						|
	opcode_template = GetOpTemplate(instruction);
 | 
						|
	sprintf(instruction_name, "%s", opcode_template->name);
 | 
						|
	if (opcode_template->extended) 
 | 
						|
		sprintf(&instruction_name[strlen(instruction_name)], "'%s", 
 | 
						|
			extOpTable[instruction & (((instruction >> 12) == 0x3) ? 0x7F : 0xFF)]->name);
 | 
						|
}
 | 
						|
bool DSPJitTester::Test(SDSP dsp_settings)
 | 
						|
{
 | 
						|
	if (be_verbose && !failed_only)
 | 
						|
	{
 | 
						|
		printf("Running %s: ", instruction_name);
 | 
						|
		DumpRegs(dsp_settings);
 | 
						|
	}
 | 
						|
	
 | 
						|
	last_input_dsp = dsp_settings;
 | 
						|
	last_int_dsp = RunInterpreter(dsp_settings);
 | 
						|
	last_jit_dsp = RunJit(dsp_settings);
 | 
						|
 | 
						|
	run_count++;
 | 
						|
	bool success = AreEqual(last_int_dsp, last_jit_dsp);
 | 
						|
	if (!success)
 | 
						|
		fail_count++;
 | 
						|
	return success;
 | 
						|
}
 | 
						|
SDSP DSPJitTester::RunInterpreter(SDSP dsp_settings)
 | 
						|
{
 | 
						|
	ResetInterpreter();
 | 
						|
	memcpy(&g_dsp, &dsp_settings, sizeof(SDSP));
 | 
						|
	ExecuteInstruction(instruction);
 | 
						|
 | 
						|
	return g_dsp;
 | 
						|
}
 | 
						|
SDSP DSPJitTester::RunJit(SDSP dsp_settings)
 | 
						|
{
 | 
						|
	ResetJit();
 | 
						|
	memcpy(&g_dsp, &dsp_settings, sizeof(SDSP));
 | 
						|
	const u8* code = jit.GetCodePtr();
 | 
						|
	jit.ABI_PushAllCalleeSavedRegsAndAdjustStack();
 | 
						|
	jit.EmitInstruction(instruction);
 | 
						|
	jit.ABI_PopAllCalleeSavedRegsAndAdjustStack();
 | 
						|
	jit.RET();
 | 
						|
	((void(*)())code)();
 | 
						|
 | 
						|
	return g_dsp;
 | 
						|
}
 | 
						|
void DSPJitTester::ResetInterpreter()
 | 
						|
{
 | 
						|
	for (int i=0; i < WRITEBACKLOGSIZE; i++)
 | 
						|
		writeBackLogIdx[i] = -1;
 | 
						|
}
 | 
						|
void DSPJitTester::ResetJit()
 | 
						|
{
 | 
						|
	jit.ClearCodeSpace();
 | 
						|
}
 | 
						|
 | 
						|
static u16 GetRegister(SDSP const &dsp, int reg) {
 | 
						|
	switch(reg) {
 | 
						|
	case DSP_REG_AR0:
 | 
						|
	case DSP_REG_AR1:
 | 
						|
	case DSP_REG_AR2:
 | 
						|
	case DSP_REG_AR3:
 | 
						|
		return dsp.r.ar[reg - DSP_REG_AR0];
 | 
						|
	case DSP_REG_IX0:
 | 
						|
	case DSP_REG_IX1:
 | 
						|
	case DSP_REG_IX2:
 | 
						|
	case DSP_REG_IX3:
 | 
						|
		return dsp.r.ix[reg - DSP_REG_IX0];
 | 
						|
	case DSP_REG_WR0:
 | 
						|
	case DSP_REG_WR1:
 | 
						|
	case DSP_REG_WR2:
 | 
						|
	case DSP_REG_WR3:
 | 
						|
		return dsp.r.wr[reg - DSP_REG_WR0];
 | 
						|
	case DSP_REG_ST0:
 | 
						|
	case DSP_REG_ST1:
 | 
						|
	case DSP_REG_ST2:
 | 
						|
	case DSP_REG_ST3:
 | 
						|
		return dsp.r.st[reg - DSP_REG_ST0];
 | 
						|
	case DSP_REG_ACH0:
 | 
						|
	case DSP_REG_ACH1:
 | 
						|
		return dsp.r.ac[reg - DSP_REG_ACH0].h;
 | 
						|
	case DSP_REG_CR:     return dsp.r.cr;
 | 
						|
	case DSP_REG_SR:     return dsp.r.sr;
 | 
						|
	case DSP_REG_PRODL:  return dsp.r.prod.l;
 | 
						|
	case DSP_REG_PRODM:  return dsp.r.prod.m;
 | 
						|
	case DSP_REG_PRODH:  return dsp.r.prod.h;
 | 
						|
	case DSP_REG_PRODM2: return dsp.r.prod.m2;
 | 
						|
	case DSP_REG_AXL0:
 | 
						|
	case DSP_REG_AXL1:
 | 
						|
		return dsp.r.ax[reg - DSP_REG_AXL0].l;
 | 
						|
	case DSP_REG_AXH0:
 | 
						|
	case DSP_REG_AXH1:
 | 
						|
		return dsp.r.ax[reg - DSP_REG_AXH0].h;
 | 
						|
	case DSP_REG_ACL0:
 | 
						|
	case DSP_REG_ACL1:
 | 
						|
		return dsp.r.ac[reg - DSP_REG_ACL0].l;
 | 
						|
	case DSP_REG_ACM0:
 | 
						|
	case DSP_REG_ACM1:
 | 
						|
		return dsp.r.ac[reg - DSP_REG_ACM0].m;
 | 
						|
	default:
 | 
						|
		_assert_msg_(DSP_CORE, 0, "cannot happen");
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void SetRegister(SDSP &dsp, int reg, u16 val) {
 | 
						|
	switch(reg) {
 | 
						|
	case DSP_REG_AR0:
 | 
						|
	case DSP_REG_AR1:
 | 
						|
	case DSP_REG_AR2:
 | 
						|
	case DSP_REG_AR3:
 | 
						|
		dsp.r.ar[reg - DSP_REG_AR0] = val; break;
 | 
						|
	case DSP_REG_IX0:
 | 
						|
	case DSP_REG_IX1:
 | 
						|
	case DSP_REG_IX2:
 | 
						|
	case DSP_REG_IX3:
 | 
						|
		dsp.r.ix[reg - DSP_REG_IX0] = val; break;
 | 
						|
	case DSP_REG_WR0:
 | 
						|
	case DSP_REG_WR1:
 | 
						|
	case DSP_REG_WR2:
 | 
						|
	case DSP_REG_WR3:
 | 
						|
		dsp.r.wr[reg - DSP_REG_WR0] = val; break;
 | 
						|
	case DSP_REG_ST0:
 | 
						|
	case DSP_REG_ST1:
 | 
						|
	case DSP_REG_ST2:
 | 
						|
	case DSP_REG_ST3:
 | 
						|
		dsp.r.st[reg - DSP_REG_ST0] = val; break;
 | 
						|
	case DSP_REG_ACH0:
 | 
						|
	case DSP_REG_ACH1:
 | 
						|
		dsp.r.ac[reg - DSP_REG_ACH0].h = val; break;
 | 
						|
	case DSP_REG_CR:     dsp.r.cr = val; break;
 | 
						|
	case DSP_REG_SR:     dsp.r.sr = val; break;
 | 
						|
	case DSP_REG_PRODL:  dsp.r.prod.l = val; break;
 | 
						|
	case DSP_REG_PRODM:  dsp.r.prod.m = val; break;
 | 
						|
	case DSP_REG_PRODH:  dsp.r.prod.h = val; break;
 | 
						|
	case DSP_REG_PRODM2: dsp.r.prod.m2 = val; break;
 | 
						|
	case DSP_REG_AXL0:
 | 
						|
	case DSP_REG_AXL1:
 | 
						|
		dsp.r.ax[reg - DSP_REG_AXL0].l = val; break;
 | 
						|
	case DSP_REG_AXH0:
 | 
						|
	case DSP_REG_AXH1:
 | 
						|
		dsp.r.ax[reg - DSP_REG_AXH0].h = val; break;
 | 
						|
	case DSP_REG_ACL0:
 | 
						|
	case DSP_REG_ACL1:
 | 
						|
		dsp.r.ac[reg - DSP_REG_ACL0].l = val; break;
 | 
						|
	case DSP_REG_ACM0:
 | 
						|
	case DSP_REG_ACM1:
 | 
						|
		dsp.r.ac[reg - DSP_REG_ACM0].m = val; break;
 | 
						|
	default:
 | 
						|
		_assert_msg_(DSP_CORE, 0, "cannot happen");
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
bool DSPJitTester::AreEqual(SDSP& int_dsp, SDSP& jit_dsp)
 | 
						|
{
 | 
						|
	bool equal = true;
 | 
						|
	for (int i = 0; i < DSP_REG_NUM; i++)
 | 
						|
	{
 | 
						|
	    if (GetRegister(int_dsp,i) != GetRegister(jit_dsp, i))
 | 
						|
		{
 | 
						|
			if (equal)
 | 
						|
			{
 | 
						|
				if (failed_only)
 | 
						|
				{
 | 
						|
					printf("%s ", instruction_name);
 | 
						|
					DumpRegs(last_input_dsp);
 | 
						|
				}
 | 
						|
				if (be_verbose || failed_only)
 | 
						|
					printf("failed\n");
 | 
						|
			}
 | 
						|
			equal = false;
 | 
						|
			if (be_verbose || failed_only)
 | 
						|
				printf("\t%s: int = 0x%04x, jit = 0x%04x\n", regnames[i].name, GetRegister(int_dsp,i), GetRegister(jit_dsp, i));
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	//TODO: more sophisticated checks?
 | 
						|
	if (!int_dsp.iram || !jit_dsp.iram)
 | 
						|
	{
 | 
						|
		if (be_verbose)
 | 
						|
			printf("(IRAM null)");
 | 
						|
	}
 | 
						|
	else if (memcmp(int_dsp.iram, jit_dsp.iram, DSP_IRAM_BYTE_SIZE))
 | 
						|
	{
 | 
						|
		printf("\tIRAM: different\n");
 | 
						|
		equal = false;
 | 
						|
	}
 | 
						|
	if (!int_dsp.dram || !jit_dsp.dram)
 | 
						|
	{
 | 
						|
		if (be_verbose)
 | 
						|
			printf("(DRAM null)");
 | 
						|
	}
 | 
						|
	else if (memcmp(int_dsp.dram, jit_dsp.dram, DSP_DRAM_BYTE_SIZE))
 | 
						|
	{
 | 
						|
		printf("\tDRAM: different\n");
 | 
						|
		equal = false;
 | 
						|
	}
 | 
						|
 | 
						|
	if (equal && be_verbose && !failed_only)
 | 
						|
		printf("passed\n");
 | 
						|
	return equal;
 | 
						|
}
 | 
						|
void DSPJitTester::Report()
 | 
						|
{
 | 
						|
	printf("%s (0x%04x): Ran %d times, Failed %d times.\n", instruction_name, instruction, run_count, fail_count);
 | 
						|
}
 | 
						|
void DSPJitTester::DumpJittedCode()
 | 
						|
{
 | 
						|
	ResetJit();
 | 
						|
	const u8* code = jit.GetCodePtr();
 | 
						|
	jit.EmitInstruction(instruction);
 | 
						|
	size_t code_size = jit.GetCodePtr() - code;
 | 
						|
 | 
						|
	printf("%s emitted: ", instruction_name);
 | 
						|
	for (size_t i = 0; i < code_size; i++)
 | 
						|
		printf("%02x ", code[i]);
 | 
						|
	printf("\n");
 | 
						|
}
 | 
						|
void DSPJitTester::DumpRegs(SDSP& dsp)
 | 
						|
{
 | 
						|
	for (int i = 0; i < DSP_REG_NUM; i++)
 | 
						|
		if (GetRegister(dsp,i))
 | 
						|
			printf("%s=0x%04x ", regnames[i].name, GetRegister(dsp,i));
 | 
						|
}
 | 
						|
void DSPJitTester::Initialize()
 | 
						|
{
 | 
						|
	//init int
 | 
						|
	InitInstructionTable();
 | 
						|
}
 | 
						|
 | 
						|
int DSPJitTester::TestOne(TestDataIterator it, SDSP& dsp)
 | 
						|
{
 | 
						|
	int failed = 0;
 | 
						|
	if (it != test_values.end())
 | 
						|
	{
 | 
						|
		u8 reg = it->first;
 | 
						|
		TestData& data = it->second;
 | 
						|
		it++;
 | 
						|
		for (TestData::size_type i = 0; i < data.size(); i++)
 | 
						|
		{
 | 
						|
			SetRegister(dsp, reg, data.at(i));
 | 
						|
			failed += TestOne(it, dsp);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		if (!Test(dsp))
 | 
						|
			failed++;
 | 
						|
	}
 | 
						|
	return failed;
 | 
						|
}
 | 
						|
int DSPJitTester::TestAll(bool verbose_fail)
 | 
						|
{
 | 
						|
	int failed = 0;
 | 
						|
 | 
						|
	SDSP dsp;
 | 
						|
	memset(&dsp, 0, sizeof(SDSP));
 | 
						|
	//from DSPCore_Init
 | 
						|
	dsp.irom = (u16*)AllocateMemoryPages(DSP_IROM_BYTE_SIZE);
 | 
						|
	dsp.iram = (u16*)AllocateMemoryPages(DSP_IRAM_BYTE_SIZE);
 | 
						|
	dsp.dram = (u16*)AllocateMemoryPages(DSP_DRAM_BYTE_SIZE);
 | 
						|
	dsp.coef = (u16*)AllocateMemoryPages(DSP_COEF_BYTE_SIZE);
 | 
						|
 | 
						|
	// Fill roms with distinct patterns.
 | 
						|
	for (int i = 0; i < DSP_IROM_SIZE; i++)
 | 
						|
	    dsp.irom[i] = (i & 0x3fff) | 0x4000;
 | 
						|
	for (int i = 0; i < DSP_COEF_SIZE; i++)
 | 
						|
	    dsp.coef[i] = (i & 0x3fff) | 0x8000;
 | 
						|
	for (int i = 0; i < DSP_DRAM_SIZE; i++)
 | 
						|
	    dsp.dram[i] = (i & 0x3fff) | 0xc000;
 | 
						|
	// Fill IRAM with HALT opcodes.
 | 
						|
	for (int i = 0; i < DSP_IRAM_SIZE; i++)
 | 
						|
		dsp.iram[i] = 0x0021; // HALT opcode
 | 
						|
 | 
						|
	bool verbose = failed_only;
 | 
						|
	failed_only = verbose_fail;
 | 
						|
	failed += TestOne(test_values.begin(), dsp);
 | 
						|
	failed_only = verbose;
 | 
						|
 | 
						|
	FreeMemoryPages(dsp.irom, DSP_IROM_BYTE_SIZE);
 | 
						|
	FreeMemoryPages(dsp.iram, DSP_IRAM_BYTE_SIZE);
 | 
						|
	FreeMemoryPages(dsp.dram, DSP_DRAM_BYTE_SIZE);
 | 
						|
	FreeMemoryPages(dsp.coef, DSP_COEF_BYTE_SIZE);
 | 
						|
 | 
						|
	return failed;
 | 
						|
}
 | 
						|
void DSPJitTester::AddTestData(u8 reg)
 | 
						|
{
 | 
						|
	AddTestData(reg, 0);
 | 
						|
	AddTestData(reg, 1);
 | 
						|
	AddTestData(reg, 0x1fff);
 | 
						|
	AddTestData(reg, 0x2000);
 | 
						|
	AddTestData(reg, 0x2001);
 | 
						|
	AddTestData(reg, 0x7fff);
 | 
						|
	AddTestData(reg, 0x8000);
 | 
						|
	AddTestData(reg, 0x8001);
 | 
						|
	AddTestData(reg, 0xfffe);
 | 
						|
	AddTestData(reg, 0xffff);
 | 
						|
}
 | 
						|
void DSPJitTester::AddTestData(u8 reg, u16 value)
 | 
						|
{
 | 
						|
	if (reg < DSP_REG_NUM)
 | 
						|
		test_values[reg].push_back(value);
 | 
						|
}
 | 
						|
 |