1 // Copyright 2017 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4
5 #include "Common/FileUtil.h"
6 #include "Core/DSP/DSPCodeUtil.h"
7 #include "Core/DSP/DSPDisassembler.h"
8
9 #include "DSPTestBinary.h"
10 #include "DSPTestText.h"
11 #include "HermesBinary.h"
12
13 #include <gtest/gtest.h>
14
RoundTrippableDissassemble(const std::vector<u16> & code,std::string & text)15 static bool RoundTrippableDissassemble(const std::vector<u16>& code, std::string& text)
16 {
17 DSP::AssemblerSettings settings;
18 settings.ext_separator = '\'';
19 settings.decode_names = true;
20 settings.decode_registers = true;
21 // These two prevent roundtripping.
22 settings.show_hex = false;
23 settings.show_pc = false;
24 DSP::DSPDisassembler disasm(settings);
25
26 return disasm.Disassemble(code, text);
27 }
28
29 // This test goes from text ASM to binary to text ASM and once again back to binary.
30 // Then the two binaries are compared.
RoundTrip(const std::vector<u16> & code1)31 static bool RoundTrip(const std::vector<u16>& code1)
32 {
33 std::vector<u16> code2;
34 std::string text;
35 if (!RoundTrippableDissassemble(code1, text))
36 {
37 printf("RoundTrip: Disassembly failed.\n");
38 return false;
39 }
40 if (!DSP::Assemble(text, code2))
41 {
42 printf("RoundTrip: Assembly failed.\n");
43 return false;
44 }
45 if (!DSP::Compare(code1, code2))
46 {
47 DSP::Disassemble(code1, true, text);
48 printf("%s", text.c_str());
49 }
50 return true;
51 }
52
53 // This test goes from text ASM to binary to text ASM and once again back to binary.
54 // Very convenient for testing. Then the two binaries are compared.
SuperTrip(const char * asm_code)55 static bool SuperTrip(const char* asm_code)
56 {
57 std::vector<u16> code1, code2;
58 std::string text;
59 if (!DSP::Assemble(asm_code, code1))
60 {
61 printf("SuperTrip: First assembly failed\n");
62 return false;
63 }
64 printf("First assembly: %i words\n", (int)code1.size());
65
66 if (!RoundTrippableDissassemble(code1, text))
67 {
68 printf("SuperTrip: Disassembly failed\n");
69 return false;
70 }
71 else
72 {
73 printf("Disassembly:\n");
74 printf("%s", text.c_str());
75 }
76
77 if (!DSP::Assemble(text, code2))
78 {
79 printf("SuperTrip: Second assembly failed\n");
80 return false;
81 }
82 return true;
83 }
84
85 // Let's start out easy - a trivial instruction..
TEST(DSPAssembly,TrivialInstruction)86 TEST(DSPAssembly, TrivialInstruction)
87 {
88 ASSERT_TRUE(SuperTrip(" NOP\n"));
89 }
90
91 // Now let's do several.
TEST(DSPAssembly,SeveralTrivialInstructions)92 TEST(DSPAssembly, SeveralTrivialInstructions)
93 {
94 ASSERT_TRUE(SuperTrip(" NOP\n"
95 " NOP\n"
96 " NOP\n"));
97 }
98
99 // Turning it up a notch.
TEST(DSPAssembly,SeveralNoParameterInstructions)100 TEST(DSPAssembly, SeveralNoParameterInstructions)
101 {
102 ASSERT_TRUE(SuperTrip(" SET16\n"
103 " SET40\n"
104 " CLR15\n"
105 " M0\n"
106 " M2\n"));
107 }
108
109 // Time to try labels and parameters, and comments.
TEST(DSPAssembly,LabelsParametersAndComments)110 TEST(DSPAssembly, LabelsParametersAndComments)
111 {
112 ASSERT_TRUE(SuperTrip("DIRQ_TEST: equ 0xfffb ; DSP Irq Request\n"
113 " si @0xfffc, #0x8888\n"
114 " si @0xfffd, #0xbeef\n"
115 " si @DIRQ_TEST, #0x0001\n"));
116 }
117
118 // Let's see if registers roundtrip. Also try predefined labels.
TEST(DSPAssembly,RegistersAndPredefinedLabels)119 TEST(DSPAssembly, RegistersAndPredefinedLabels)
120 {
121 ASSERT_TRUE(SuperTrip(" si @0xfffc, #0x8888\n"
122 " si @0xfffd, #0xbeef\n"
123 " si @DIRQ, #0x0001\n"));
124 }
125
126 // Let's try some messy extended instructions.
TEST(DSPAssembly,ExtendedInstructions)127 TEST(DSPAssembly, ExtendedInstructions)
128 {
129 ASSERT_TRUE(SuperTrip(" MULMV'SN $AX0.L, $AX0.H, $ACC0 : @$AR2, $AC1.M\n"
130 " ADDAXL'MV $ACC1, $AX1.L : $AX1.H, $AC1.M\n"));
131 }
132
TEST(DSPAssembly,HermesBinary)133 TEST(DSPAssembly, HermesBinary)
134 {
135 ASSERT_TRUE(RoundTrip(s_hermes_bin));
136 }
137
TEST(DSPAssembly,DSPTestText)138 TEST(DSPAssembly, DSPTestText)
139 {
140 ASSERT_TRUE(SuperTrip(s_dsp_test_text));
141 }
142
TEST(DSPAssembly,DSPTestBinary)143 TEST(DSPAssembly, DSPTestBinary)
144 {
145 ASSERT_TRUE(RoundTrip(s_dsp_test_bin));
146 }
147
148 /*
149
150 if (File::ReadFileToString("C:/devkitPro/examples/wii/asndlib/dsptest/dsp_test.ds", &dsp_test))
151 SuperTrip(dsp_test.c_str());
152
153 //.File::ReadFileToString("C:/devkitPro/trunk/libogc/libasnd/dsp_mixer/dsp_mixer.s", &dsp_test);
154 // This is CLOSE to working. Sorry about the local path btw. This is preliminary code.
155 */
156