moar testing! changed some things to make it easier to use, added some bits of documentation for other devs eager to use it :)

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5358 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
j4ck.fr0st 2010-04-13 19:31:31 +00:00
parent 122d5e7b4e
commit 578828a142
3 changed files with 227 additions and 65 deletions

View file

@ -2,69 +2,78 @@
void nx_dr()
{
SDSP test_dsp;
DSPJitTester tester(0x40, 0x04);
for (u16 input_reg = 0; input_reg < 50; input_reg++)
for (u16 input_wr0 = 0; input_wr0 < 10; input_wr0++)
{
memset(&test_dsp, 0, sizeof(SDSP));
test_dsp.r[DSP_REG_WR0] = input_wr0;
test_dsp.r[0] = input_reg;
if (!tester.Test(test_dsp))
{
printf("%s Test failed: in = 0x%04x, wr0 = 0x%04x > int = 0x%04x, jit = 0x%04x\n",
tester.GetInstructionName(),
input_reg, input_wr0,
tester.GetLastInterpreterDSP().r[0], tester.GetLastJitDSP().r[0]);
}
}
DSPJitTester tester(0x8000, 0x0004);
tester.AddTestData(DSP_REG_ACC0);
tester.AddTestData(DSP_REG_WR0);
tester.TestAll();
tester.Report();
}
void nx_ir()
{
SDSP test_dsp;
DSPJitTester tester(0x40, 0x08);
for (u16 input_reg = 0; input_reg < 50; input_reg++)
for (u16 input_wr0 = 0; input_wr0 < 10; input_wr0++)
{
memset(&test_dsp, 0, sizeof(SDSP));
test_dsp.r[DSP_REG_WR0] = input_wr0;
test_dsp.r[0] = input_reg;
if (!tester.Test(test_dsp))
{
printf("%s Test failed: in = 0x%04x, wr0 = 0x%04x > int = 0x%04x, jit = 0x%04x\n",
tester.GetInstructionName(),
input_reg, input_wr0,
tester.GetLastInterpreterDSP().r[0], tester.GetLastJitDSP().r[0]);
}
}
DSPJitTester tester(0x8000, 0x0008);
tester.AddTestData(DSP_REG_ACC0);
tester.AddTestData(DSP_REG_WR0);
tester.TestAll();
tester.Report();
}
void nx_nr()
{
SDSP test_dsp;
DSPJitTester tester(0x40, 0x0c);
DSPJitTester tester(0x8000, 0x000c);
tester.AddTestData(DSP_REG_ACC0);
tester.AddTestData(DSP_REG_WR0);
tester.AddTestData(DSP_REG_IX0);
tester.TestAll(true);
tester.Report();
}
for (u16 input_reg = 0; input_reg < 10; input_reg++)
for (u16 input_wr0 = 0; input_wr0 < 10; input_wr0++)
for (u16 input_ix0 = 0; input_ix0 < 10; input_ix0++)
{
memset(&test_dsp, 0, sizeof(SDSP));
test_dsp.r[DSP_REG_IX0] = input_ix0;
test_dsp.r[DSP_REG_WR0] = input_wr0;
test_dsp.r[0] = input_reg;
if (!tester.Test(test_dsp))
{
printf("%s Test failed: in = 0x%04x, wr0 = 0x%04x, ix0 = 0x%04x > int = 0x%04x, jit = 0x%04x\n",
tester.GetInstructionName(),
input_reg, input_wr0, input_ix0,
tester.GetLastInterpreterDSP().r[0], tester.GetLastJitDSP().r[0]);
}
}
void dar()
{
DSPJitTester tester(0x0004);
tester.AddTestData(DSP_REG_ACC0);
tester.AddTestData(DSP_REG_WR0);
tester.TestAll();
tester.Report();
}
void iar()
{
DSPJitTester tester(0x0008);
tester.AddTestData(DSP_REG_ACC0);
tester.AddTestData(DSP_REG_WR0);
tester.TestAll();
tester.Report();
}
void subarn()
{
DSPJitTester tester(0x000c);
tester.AddTestData(DSP_REG_ACC0);
tester.AddTestData(DSP_REG_WR0);
tester.AddTestData(DSP_REG_IX0);
tester.TestAll();
tester.Report();
}
void addarn()
{
DSPJitTester tester(0x0010);
tester.AddTestData(DSP_REG_ACC0);
tester.AddTestData(DSP_REG_WR0);
tester.AddTestData(DSP_REG_IX0);
tester.TestAll();
tester.Report();
}
void sbclr()
{
DSPJitTester tester(0x1200);
tester.AddTestData(DSP_REG_SR);
tester.TestAll();
tester.Report();
}
void sbset()
{
DSPJitTester tester(0x1300);
tester.AddTestData(DSP_REG_SR);
tester.TestAll();
tester.Report();
}
@ -72,6 +81,13 @@ void AudioJitTests()
{
DSPJitTester::Initialize();
dar();
iar();
subarn();
addarn();
sbclr();
sbset();
nx_ir();
nx_dr();
nx_nr();

View file

@ -1,9 +1,9 @@
#include "DSPJitTester.h"
DSPJitTester::DSPJitTester(u16 opcode, u16 opcode_ext, bool verbose)
: be_verbose(verbose), run_count(0), fail_count(0)
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 << 9 | opcode_ext;
instruction = opcode | opcode_ext;
opcode_template = GetOpTemplate(instruction);
sprintf(instruction_name, "%s", opcode_template->name);
if (opcode_template->extended)
@ -12,9 +12,13 @@ DSPJitTester::DSPJitTester(u16 opcode, u16 opcode_ext, bool verbose)
}
bool DSPJitTester::Test(SDSP dsp_settings)
{
if (be_verbose)
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);
@ -55,18 +59,26 @@ void DSPJitTester::ResetJit()
bool DSPJitTester::AreEqual(SDSP& int_dsp, SDSP& jit_dsp)
{
bool equal = true;
for (int i = 0; i < 32; i++)
for (int i = 0; i < DSP_REG_NUM; i++)
{
if (int_dsp.r[i] != jit_dsp.r[i])
{
if (equal && be_verbose)
printf("failed\n");
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)
if (be_verbose || failed_only)
printf("\t%s: int = 0x%04x, jit = 0x%04x\n", regnames[i].name, int_dsp.r[i], jit_dsp.r[i]);
}
}
if (equal && be_verbose)
if (equal && be_verbose && !failed_only)
printf("passed\n");
return equal;
}
@ -86,8 +98,68 @@ void DSPJitTester::DumpJittedCode()
printf("%02x ", code[i]);
printf("\n");
}
void DSPJitTester::DumpRegs(SDSP& dsp)
{
for (int i = 0; i < DSP_REG_NUM; i++)
if (dsp.r[i])
printf("%s=0x%04x ", regnames[i].name, dsp.r[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++)
{
dsp.r[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));
bool verbose = failed_only;
failed_only = verbose_fail;
failed += TestOne(test_values.begin(), dsp);
failed_only = verbose;
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);
}

View file

@ -1,11 +1,76 @@
// How to use the DSPJitTester:
//
// == Before running ==
// Make sure to call Initialize to set initial stuff required by int and jit:
// DSPJitTester::Initialize();
//
// == Creation of a testcase ==
// Create a testcase for a normal operation:
// DSPJitTester tester(0x0004); //taken from DSPTables.cpp, opcodes[]
//
// Create a testcase for an extended operation:
// DSPJitTester tester(0x8000, 0x0004); //NX from opcodes, DR from opcodes_ext
//
// By default, no messages are written.
// To log all operations, set verbose to true:
// DSPJitTester tester(0x8000, 0x0004, true);
//
// You can also choose to only print failing tests:
// DSPJitTester tester(0x8000, 0x0004, verbosity_setting, true);
// verbose = true will give the same output as verbose,
// while verbose = false will only (really!) print failing tests.
//
// == Setting up values ==
// You can set the tester up with values for each DSP register:
// tester.AddTestData(DSP_REG_ACC0, 1);
// tester.AddTestData(DSP_REG_ACC0, 2);
// tester.AddTestData(DSP_REG_ACC0, 3);
//
// You can also choose to have a few predefined values added for a register:
// tester.AddTestData(DSP_REG_ACC0); //see the method body for the values added
//
// == Running the tests ==
// After setup, you can either run JIT against the interpreter
// using all predefined register values, pass your own set of
// registers or run either of the two independently from each other.
//
// int failed_tests = tester.TestAll(); //run jit against int, using values from AddTestData
// int failed_tests = tester.TestAll(true); //override the value for only_failed to show failure
//
// SDSP dsp = GetCustomSetOfRegisters();
// bool success = tester.Test(dsp); //run jit against int, using a custom set of register values
//
// SDSP result = tester.RunInterpreter(dsp); //run int alone
// SDSP result = tester.RunJit(dsp); //run jit alone
//
// == Examining results ==
// When either verbose or only_failed is set to true, the tester will automatically report
// failure to stdout, along with input registers and the differences in output registers.
//
// tester.Report(); //display a small report afterwards
//
// SDSP int = tester.GetLastInterpreterDSP(); //examine the DSP set left after running int
// SDSP jit = tester.GetLastJitDSP(); //same for jit
//
// int tests_run = tester.GetRunCount();
// int tests_failed = tester.GetFailCount();
// const char* tested_instruction = tester.GetInstructionName();
// printf("%s ran %d tests and failed %d times\n", tested_instruction, tests_run, tests_failed);
//
// tester.DumpJittedCode(); //prints the code bytes produced by jit (examine with udcli/udis86 or similar)
#ifndef __DSP_JIT_TESTER_
#define __DSP_JIT_TESTER_
#include "DSPCore.h"
#include "DSPInterpreter.h"
//#include "DSPIntExtOps.h"
//
//#include "x64Emitter.h"
#include <map>
#include <vector>
typedef std::vector<u16> TestData;
typedef std::map<u8, TestData> TestDataList;
typedef TestDataList::iterator TestDataIterator;
#define DSP_REG_NUM 32
class DSPJitTester
{
@ -14,15 +79,24 @@ class DSPJitTester
DSPEmitter jit;
SDSP last_int_dsp;
SDSP last_jit_dsp;
SDSP last_input_dsp;
bool be_verbose;
bool failed_only;
int run_count;
int fail_count;
char instruction_name[16];
TestDataList test_values;
bool AreEqual(SDSP&, SDSP&);
int TestOne(TestDataIterator, SDSP&);
void DumpRegs(SDSP&);
public:
DSPJitTester(u16 opcode, u16 opcode_ext, bool verbose = false);
DSPJitTester(u16 opcode, u16 opcode_ext = 0, bool verbose = false, bool only_failed = false);
bool Test(SDSP);
int TestAll() { return TestAll(failed_only); }
int TestAll(bool verbose_fail);
void AddTestData(u8 reg);
void AddTestData(u8 reg, u16 value);
SDSP RunInterpreter(SDSP);
SDSP RunJit(SDSP);
void ResetInterpreter();