1 #include <string>
2 #include <unordered_map>
3 #include <vector>
4 #include <3ds.h>
5 #include <arpa/inet.h>
6 #include <malloc.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <sys/socket.h>
10 
11 #include "cdc_bin.h"
12 
13 
14 PrintConsole topScreen, bottomScreen;
15 
MoveCursor(unsigned row,unsigned col)16 void MoveCursor(unsigned row, unsigned col) {
17     printf("\x1b[%u;%uH", row + 1, col + 1);
18 }
19 
20 enum Color {
21     Reset = 0,
22     Black = 30,
23     Red = 31,
24     Green = 32,
25     Yellow = 33,
26     Blue = 34,
27     Magnenta = 35,
28     Cyan = 36,
29     White = 37,
30 };
SetColor(Color color,Color background)31 void SetColor(Color color, Color background) {
32     printf("\x1b[%dm\x1b[%dm", (int)color, (int)background + 10);
33 }
34 
35 
36 
FlushCache(void * ptr,u32 size)37 void FlushCache(void* ptr, u32 size) {
38     svcFlushProcessDataCache(CUR_PROCESS_HANDLE, ptr, size);
39 }
40 
InvalidateCache(void * ptr,u32 size)41 void InvalidateCache(void* ptr, u32 size) {
42     svcInvalidateProcessDataCache(CUR_PROCESS_HANDLE, ptr, size);
43 }
44 
45 
46 vu16* dspP = (vu16*)0x1FF00000;
47 vu16* dspD = (vu16*)0x1FF40000;
48 
49 u32 playground_size = 0x80;
50 
51 vu8* dsp_playground = (vu8*)(dspD + 0x1000); // note: address = 0x1000 in dsp space
52 vu8* fcram_playground;
53 
PrintAll()54 void PrintAll() {
55     consoleSelect(&topScreen);
56 
57     MoveCursor(0, 0);
58     printf("DSP @ 0x1000:\n");
59 
60     InvalidateCache((void*)dsp_playground, playground_size);
61     for (u32 i = 0; i < playground_size; ++i) {
62         u8 v = dsp_playground[i];
63         if (v != i) {
64             SetColor(Green, Black);
65         }
66         printf("%02X", v);
67         SetColor(Reset, Reset);
68         if (i % 16 == 15) {
69             printf("\n");
70         } else {
71             printf(" ");
72         }
73     }
74 
75 
76     u32 addr = (u32)fcram_playground;
77     if (addr < 0x1C000000) {
78         addr = addr - 0x14000000 + 0x20000000;
79     } else {
80         addr = addr - 0x30000000 + 0x20000000;
81     }
82     printf("\nFCRAM @ 0x%08lX:\n", addr);
83 
84     InvalidateCache((void*)fcram_playground, playground_size);
85     for (u32 i = 0; i < playground_size; ++i) {
86         u8 v = fcram_playground[i];
87         if (v != (i | 0x80)) {
88             SetColor(Green, Black);
89         }
90         printf("%02X", v);
91         SetColor(Reset, Reset);
92         if (i % 16 == 15) {
93             printf("\n");
94         } else {
95             printf(" ");
96         }
97     }
98 
99 
100     consoleSelect(&bottomScreen);
101 }
102 
ResetDspPlayground()103 void ResetDspPlayground() {
104     InvalidateCache((void*)dsp_playground, playground_size);
105     for (u32 i = 0; i < playground_size; ++i) {
106         dsp_playground[i] = i;
107     }
108     FlushCache((void*)dsp_playground, playground_size);
109 }
110 
ResetFcramPlayground()111 void ResetFcramPlayground() {
112     InvalidateCache((void*)fcram_playground, playground_size);
113     for (u32 i = 0; i < playground_size; ++i) {
114         fcram_playground[i] = i | 0x80;
115     }
116     FlushCache((void*)fcram_playground, playground_size);
117 }
118 
119 int udp_s;
120 int udp_s_broadcast;
121 
UdpInit()122 void UdpInit() {
123 #define SOC_ALIGN 0x1000
124 #define SOC_BUFFERSIZE 0x100000
125     static u32* SOC_buffer;
126     // allocate buffer for SOC service
127     SOC_buffer = (u32*)memalign(SOC_ALIGN, SOC_BUFFERSIZE);
128     if (SOC_buffer == NULL) {
129         printf("memalign: failed to allocate\n");
130         return;
131     }
132 
133     Result ret;
134     if ((ret = socInit(SOC_buffer, SOC_BUFFERSIZE)) != 0) {
135         printf("socInit: 0x%08lX\n", ret);
136         return;
137     }
138 
139     sockaddr_in si_me;
140 
141     // create a UDP socket
142     if ((udp_s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
143         printf("socket() failed\n");
144         return;
145     }
146 
147     // zero out the structure
148     memset(&si_me, 0, sizeof(si_me));
149 
150     si_me.sin_family = AF_INET;
151     si_me.sin_port = htons(8888);
152     si_me.sin_addr.s_addr = htonl(INADDR_ANY);
153 
154     // bind socket to port
155     if (bind(udp_s, (sockaddr*)&si_me, sizeof(si_me)) == -1) {
156         printf("bind() failed\n");
157         return;
158     }
159 
160     // create a UDP broadcast socket
161     if ((udp_s_broadcast = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
162         printf("socket()(broadcast) failed\n");
163         return;
164     }
165 }
166 
167 constexpr unsigned BUFLEN = 512;
168 char buf[BUFLEN];
169 
Fire()170 void Fire() {
171     dspD[0] = 1;
172     FlushCache((void*)dspD, 8);
173     while(true) {
174         InvalidateCache((void*)dspD, 8);
175         if (dspD[0] == 0)
176             break;
177     }
178 }
179 
CheckPackage()180 void CheckPackage() {
181     sockaddr_in si_other;
182     socklen_t slen = sizeof(si_other);
183     int recv_len;
184     if ((recv_len = recvfrom(udp_s, buf, BUFLEN, MSG_DONTWAIT, (sockaddr*)&si_other, &slen)) < 4)
185         return;
186     u16 magic;
187     memcpy(&magic, buf, 2);
188     if (magic == 0xD592) {
189         std::vector<u16> command_package((recv_len - 2) / 2);
190         printf("Command received\n");
191         memcpy(command_package.data(), buf + 2, command_package.size() * 2);
192         switch (command_package[0]) {
193         case 0: {
194             if (command_package.size() != 2) {
195                 printf("Wrong length for Read\n");
196                 break;
197             }
198             u16 addr = command_package[1];
199             printf("Read  [%04X] -> ", addr);
200             dspD[1] = 0;
201             dspD[2] = addr;
202             dspD[3] = 0xCCCC;
203 
204             Fire();
205 
206             printf("%04X\n", dspD[3]);
207             break;
208         }
209         case 1: {
210             if (command_package.size() != 3) {
211                 printf("Wrong length for Write\n");
212                 break;
213             }
214             u16 addr = command_package[1];
215             u16 value = command_package[2];
216             printf("Write [%04X] <- %04X", addr, value);
217             dspD[1] = 1;
218             dspD[2] = addr;
219             dspD[3] = value;
220 
221             Fire();
222 
223             printf(" OK\n");
224             break;
225         }
226         }
227     }
228 }
229 
main()230 int main() {
231     fcram_playground = (vu8*)linearAlloc(playground_size);
232     ResetDspPlayground();
233     ResetFcramPlayground();
234     aptInit();
235     gfxInitDefault();
236 
237     consoleInit(GFX_TOP, &topScreen);
238     consoleInit(GFX_BOTTOM, &bottomScreen);
239 
240     consoleSelect(&bottomScreen);
241     printf("Hello!\n");
242 
243     UdpInit();
244 
245     printf("dspInit: %08lX\n", dspInit());
246     bool loaded = false;
247     printf("DSP_LoadComponent: %08lX\n",
248            DSP_LoadComponent(cdc_bin, cdc_bin_size, 0xFF, 0xFF, &loaded));
249     printf("loaded = %d\n", loaded);
250 
251     svcSleepThread(1000000000);
252     char hostname[100];
253     gethostname(hostname, 100);
254     printf("IP: %s port: 8888\n", hostname);
255 
256     // Main loop
257     while (aptMainLoop()) {
258         hidScanInput();
259 
260         u32 kDown = hidKeysDown();
261 
262         if (kDown & KEY_START)
263             break;
264 
265         if (kDown & KEY_A) {
266             ResetDspPlayground();
267             printf("Reset DSP playground\n");
268         }
269 
270         if (kDown & KEY_B) {
271             ResetFcramPlayground();
272             printf("Reset FCRAM playground\n");
273         }
274 
275         CheckPackage();
276 
277         PrintAll();
278 
279         // Flush and swap framebuffers
280         gfxFlushBuffers();
281         gfxSwapBuffers();
282 
283         // Wait for VBlank
284         gspWaitForVBlank();
285     }
286     socExit();
287     dspExit();
288     gfxExit();
289     aptExit();
290     return 0;
291 }
292