mirror of
				https://github.com/dolphin-emu/dolphin.git
				synced 2025-10-25 17:39:09 +00:00 
			
		
		
		
	SPDX standardizes how source code conveys its copyright and licensing information. See https://spdx.github.io/spdx-spec/1-rationale/ . SPDX tags are adopted in many large projects, including things like the Linux kernel.
		
			
				
	
	
		
			154 lines
		
	
	
	
		
			3.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			154 lines
		
	
	
	
		
			3.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright 2017 Dolphin Emulator Project
 | |
| // SPDX-License-Identifier: GPL-2.0-or-later
 | |
| 
 | |
| #include "Common/FileUtil.h"
 | |
| #include "Core/DSP/DSPCodeUtil.h"
 | |
| #include "Core/DSP/DSPDisassembler.h"
 | |
| 
 | |
| #include "DSPTestBinary.h"
 | |
| #include "DSPTestText.h"
 | |
| #include "HermesBinary.h"
 | |
| 
 | |
| #include <gtest/gtest.h>
 | |
| 
 | |
| static bool RoundTrippableDissassemble(const std::vector<u16>& code, std::string& text)
 | |
| {
 | |
|   DSP::AssemblerSettings settings;
 | |
|   settings.ext_separator = '\'';
 | |
|   settings.decode_names = true;
 | |
|   settings.decode_registers = true;
 | |
|   // These two prevent roundtripping.
 | |
|   settings.show_hex = false;
 | |
|   settings.show_pc = false;
 | |
|   DSP::DSPDisassembler disasm(settings);
 | |
| 
 | |
|   return disasm.Disassemble(code, text);
 | |
| }
 | |
| 
 | |
| // This test goes from text ASM to binary to text ASM and once again back to binary.
 | |
| // Then the two binaries are compared.
 | |
| static bool RoundTrip(const std::vector<u16>& code1)
 | |
| {
 | |
|   std::vector<u16> code2;
 | |
|   std::string text;
 | |
|   if (!RoundTrippableDissassemble(code1, text))
 | |
|   {
 | |
|     printf("RoundTrip: Disassembly failed.\n");
 | |
|     return false;
 | |
|   }
 | |
|   if (!DSP::Assemble(text, code2))
 | |
|   {
 | |
|     printf("RoundTrip: Assembly failed.\n");
 | |
|     return false;
 | |
|   }
 | |
|   if (!DSP::Compare(code1, code2))
 | |
|   {
 | |
|     DSP::Disassemble(code1, true, text);
 | |
|     printf("%s", text.c_str());
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // This test goes from text ASM to binary to text ASM and once again back to binary.
 | |
| // Very convenient for testing. Then the two binaries are compared.
 | |
| static bool SuperTrip(const char* asm_code)
 | |
| {
 | |
|   std::vector<u16> code1, code2;
 | |
|   std::string text;
 | |
|   if (!DSP::Assemble(asm_code, code1))
 | |
|   {
 | |
|     printf("SuperTrip: First assembly failed\n");
 | |
|     return false;
 | |
|   }
 | |
|   printf("First assembly: %i words\n", (int)code1.size());
 | |
| 
 | |
|   if (!RoundTrippableDissassemble(code1, text))
 | |
|   {
 | |
|     printf("SuperTrip: Disassembly failed\n");
 | |
|     return false;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     printf("Disassembly:\n");
 | |
|     printf("%s", text.c_str());
 | |
|   }
 | |
| 
 | |
|   if (!DSP::Assemble(text, code2))
 | |
|   {
 | |
|     printf("SuperTrip: Second assembly failed\n");
 | |
|     return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Let's start out easy - a trivial instruction..
 | |
| TEST(DSPAssembly, TrivialInstruction)
 | |
| {
 | |
|   ASSERT_TRUE(SuperTrip("	NOP\n"));
 | |
| }
 | |
| 
 | |
| // Now let's do several.
 | |
| TEST(DSPAssembly, SeveralTrivialInstructions)
 | |
| {
 | |
|   ASSERT_TRUE(SuperTrip("	NOP\n"
 | |
|                         "	NOP\n"
 | |
|                         "	NOP\n"));
 | |
| }
 | |
| 
 | |
| // Turning it up a notch.
 | |
| TEST(DSPAssembly, SeveralNoParameterInstructions)
 | |
| {
 | |
|   ASSERT_TRUE(SuperTrip("	SET16\n"
 | |
|                         "	SET40\n"
 | |
|                         "	CLR15\n"
 | |
|                         "	M0\n"
 | |
|                         "	M2\n"));
 | |
| }
 | |
| 
 | |
| // Time to try labels and parameters, and comments.
 | |
| TEST(DSPAssembly, LabelsParametersAndComments)
 | |
| {
 | |
|   ASSERT_TRUE(SuperTrip("DIRQ_TEST:	equ	0xfffb	; DSP Irq Request\n"
 | |
|                         "	si		@0xfffc, #0x8888\n"
 | |
|                         "	si		@0xfffd, #0xbeef\n"
 | |
|                         "	si		@DIRQ_TEST, #0x0001\n"));
 | |
| }
 | |
| 
 | |
| // Let's see if registers roundtrip. Also try predefined labels.
 | |
| TEST(DSPAssembly, RegistersAndPredefinedLabels)
 | |
| {
 | |
|   ASSERT_TRUE(SuperTrip("	si		@0xfffc, #0x8888\n"
 | |
|                         "	si		@0xfffd, #0xbeef\n"
 | |
|                         "	si		@DIRQ, #0x0001\n"));
 | |
| }
 | |
| 
 | |
| // Let's try some messy extended instructions.
 | |
| TEST(DSPAssembly, ExtendedInstructions)
 | |
| {
 | |
|   ASSERT_TRUE(SuperTrip("   MULMV'SN    $AX0.L, $AX0.H, $ACC0 : @$AR2, $AC1.M\n"
 | |
|                         "   ADDAXL'MV   $ACC1, $AX1.L : $AX1.H, $AC1.M\n"));
 | |
| }
 | |
| 
 | |
| TEST(DSPAssembly, HermesBinary)
 | |
| {
 | |
|   ASSERT_TRUE(RoundTrip(s_hermes_bin));
 | |
| }
 | |
| 
 | |
| TEST(DSPAssembly, DSPTestText)
 | |
| {
 | |
|   ASSERT_TRUE(SuperTrip(s_dsp_test_text));
 | |
| }
 | |
| 
 | |
| TEST(DSPAssembly, DSPTestBinary)
 | |
| {
 | |
|   ASSERT_TRUE(RoundTrip(s_dsp_test_bin));
 | |
| }
 | |
| 
 | |
| /*
 | |
| 
 | |
| if (File::ReadFileToString("C:/devkitPro/examples/wii/asndlib/dsptest/dsp_test.ds", &dsp_test))
 | |
|   SuperTrip(dsp_test.c_str());
 | |
| 
 | |
| //.File::ReadFileToString("C:/devkitPro/trunk/libogc/libasnd/dsp_mixer/dsp_mixer.s", &dsp_test);
 | |
| // This is CLOSE to working. Sorry about the local path btw. This is preliminary code.
 | |
| */
 |