From 578828a14203dbf255118669daab5410ab44ea71 Mon Sep 17 00:00:00 2001 From: "j4ck.fr0st" Date: Tue, 13 Apr 2010 19:31:31 +0000 Subject: [PATCH] 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 --- Source/UnitTests/AudioJitTests.cpp | 120 ++++++++++++++++------------- Source/UnitTests/DSPJitTester.cpp | 90 +++++++++++++++++++--- Source/UnitTests/DSPJitTester.h | 82 +++++++++++++++++++- 3 files changed, 227 insertions(+), 65 deletions(-) diff --git a/Source/UnitTests/AudioJitTests.cpp b/Source/UnitTests/AudioJitTests.cpp index ec4a21c4af..da38a05aa4 100644 --- a/Source/UnitTests/AudioJitTests.cpp +++ b/Source/UnitTests/AudioJitTests.cpp @@ -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(); diff --git a/Source/UnitTests/DSPJitTester.cpp b/Source/UnitTests/DSPJitTester.cpp index 2c1467f485..2e7d91fffd 100644 --- a/Source/UnitTests/DSPJitTester.cpp +++ b/Source/UnitTests/DSPJitTester.cpp @@ -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); } \ No newline at end of file diff --git a/Source/UnitTests/DSPJitTester.h b/Source/UnitTests/DSPJitTester.h index b1e3360329..459a137a7c 100644 --- a/Source/UnitTests/DSPJitTester.h +++ b/Source/UnitTests/DSPJitTester.h @@ -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 +#include + +typedef std::vector TestData; +typedef std::map 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();