1 #include <atomic>
2 #include <string>
3 #include <unordered_map>
4 #include <vector>
5 #include <3ds.h>
6 #include <arpa/inet.h>
7 #include <malloc.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <sys/socket.h>
11
12 #include "cdc_bin.h"
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
FlushCache(volatile void * ptr,u32 size)35 void FlushCache(volatile void* ptr, u32 size) {
36 svcFlushProcessDataCache(CUR_PROCESS_HANDLE, (void*)ptr, size);
37 }
38
InvalidateCache(volatile void * ptr,u32 size)39 void InvalidateCache(volatile void* ptr, u32 size) {
40 svcInvalidateProcessDataCache(CUR_PROCESS_HANDLE, (void*)ptr, size);
41 }
42
43 vu16* dspP = (vu16*)0x1FF00000;
44 vu16* dspD = (vu16*)0x1FF40000;
45
46 std::atomic<int> interrupt_counter;
47
PrintAll()48 void PrintAll() {
49 consoleSelect(&topScreen);
50
51 MoveCursor(0, 0);
52 printf("DSP registers:\n");
53
54 InvalidateCache(dspD + 4, 2 * 8);
55
56 printf("SetSem = %04X\n", dspD[5]);
57 printf("MskSem = %04X\n", dspD[6]);
58 printf("AckSem = %04X\n", dspD[7]);
59 printf("GetSem = %04X\n", dspD[8]);
60 printf("IrqMsk = %04X\n", dspD[9]);
61 printf("Status = %04X\n", dspD[10]);
62 printf("?????? = %04X\n", dspD[11]);
63 printf("interrupt = %d\n", dspD[4]);
64
65 printf("\nCPU registers:\n");
66 printf("PCFG = %04X\n", *(vu16*)0x1ed03008);
67 printf("PSTS = %04X\n", *(vu16*)0x1ed0300C);
68 printf("PSEM = %04X\n", *(vu16*)0x1ed03010);
69 printf("PMASK = %04X\n", *(vu16*)0x1ed03014);
70 printf("PCLEAR = %04X\n", *(vu16*)0x1ed03018);
71 printf("SEM = %04X\n", *(vu16*)0x1ed0301C);
72 printf("interrupt = %d\n", (int)interrupt_counter);
73
74 consoleSelect(&bottomScreen);
75 }
76
77 int udp_s;
78 int udp_s_broadcast;
79
UdpInit()80 void UdpInit() {
81 #define SOC_ALIGN 0x1000
82 #define SOC_BUFFERSIZE 0x100000
83 static u32* SOC_buffer;
84 // allocate buffer for SOC service
85 SOC_buffer = (u32*)memalign(SOC_ALIGN, SOC_BUFFERSIZE);
86 if (SOC_buffer == NULL) {
87 printf("memalign: failed to allocate\n");
88 return;
89 }
90
91 Result ret;
92 if ((ret = socInit(SOC_buffer, SOC_BUFFERSIZE)) != 0) {
93 printf("socInit: 0x%08lX\n", ret);
94 return;
95 }
96
97 sockaddr_in si_me;
98
99 // create a UDP socket
100 if ((udp_s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
101 printf("socket() failed\n");
102 return;
103 }
104
105 // zero out the structure
106 memset(&si_me, 0, sizeof(si_me));
107
108 si_me.sin_family = AF_INET;
109 si_me.sin_port = htons(8888);
110 si_me.sin_addr.s_addr = htonl(INADDR_ANY);
111
112 // bind socket to port
113 if (bind(udp_s, (sockaddr*)&si_me, sizeof(si_me)) == -1) {
114 printf("bind() failed\n");
115 return;
116 }
117
118 // create a UDP broadcast socket
119 if ((udp_s_broadcast = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
120 printf("socket()(broadcast) failed\n");
121 return;
122 }
123 }
124
125 constexpr unsigned BUFLEN = 512;
126 char buf[BUFLEN];
127
Fire()128 void Fire() {
129 dspD[0] = 1;
130 FlushCache((void*)dspD, 8);
131 while (true) {
132 InvalidateCache((void*)dspD, 8);
133 if (dspD[0] == 0)
134 break;
135 }
136 }
137
CheckPackage()138 void CheckPackage() {
139 sockaddr_in si_other;
140 socklen_t slen = sizeof(si_other);
141 int recv_len;
142 if ((recv_len = recvfrom(udp_s, buf, BUFLEN, MSG_DONTWAIT, (sockaddr*)&si_other, &slen)) < 4)
143 return;
144 u16 magic;
145 memcpy(&magic, buf, 2);
146 if (magic == 0xD592) {
147 std::vector<u16> command_package((recv_len - 2) / 2);
148 printf("Command received\n");
149 memcpy(command_package.data(), buf + 2, command_package.size() * 2);
150 switch (command_package[0]) {
151 case 0: {
152 if (command_package.size() != 2) {
153 printf("Wrong length for Read\n");
154 break;
155 }
156 u16 addr = command_package[1];
157 printf("Read [%04X] -> ", addr);
158 dspD[1] = 0;
159 dspD[2] = addr;
160 dspD[3] = 0xCCCC;
161
162 Fire();
163
164 printf("%04X\n", dspD[3]);
165 break;
166 }
167 case 1: {
168 if (command_package.size() != 3) {
169 printf("Wrong length for Write\n");
170 break;
171 }
172 u16 addr = command_package[1];
173 u16 value = command_package[2];
174 printf("Write [%04X] <- %04X", addr, value);
175 dspD[1] = 1;
176 dspD[2] = addr;
177 dspD[3] = value;
178
179 Fire();
180
181 printf(" OK\n");
182 break;
183 }
184 case 2: {
185 if (command_package.size() != 3) {
186 printf("Wrong length for CPU Read\n");
187 break;
188 }
189 u32 addr = command_package[1] | ((u32)command_package[2] << 16);
190 printf("Read CPU [%08lX] -> ", addr);
191 // FlushCache((vu16*)addr, 2);
192 printf("%04X\n", *(vu16*)(addr));
193 break;
194 }
195 case 3: {
196 if (command_package.size() != 4) {
197 printf("Wrong length for CPU Write\n");
198 break;
199 }
200 u32 addr = command_package[1] | ((u32)command_package[2] << 16);
201 u16 value = command_package[3];
202 printf("Write CPU [%08lX] <- %04X", addr, value);
203 // InvalidateCache((vu16*)addr, 2);
204 *(vu16*)(addr) = value;
205 printf(" OK\n");
206 break;
207 }
208 }
209 }
210 }
211
212 Handle pmHandle;
pmInit_(void)213 Result pmInit_(void) {
214 Result res = srvGetServiceHandle(&pmHandle, "pm:app");
215 return res;
216 }
pmExit_(void)217 void pmExit_(void) {
218 svcCloseHandle(pmHandle);
219 }
220
PM_TerminateTitle(u64 tid,u64 timeout)221 Result PM_TerminateTitle(u64 tid, u64 timeout) {
222 Result ret = 0;
223 u32* cmdbuf = getThreadCommandBuffer();
224
225 cmdbuf[0] = IPC_MakeHeader(0x4, 4, 0);
226 cmdbuf[1] = tid & 0xFFFFFFFF;
227 cmdbuf[2] = tid >> 32;
228 cmdbuf[3] = timeout & 0xffffffff;
229 cmdbuf[4] = (timeout >> 32) & 0xffffffff;
230
231 if (R_FAILED(ret = svcSendSyncRequest(pmHandle)))
232 return ret;
233
234 return (Result)cmdbuf[1];
235 }
236
237 Handle dsp_interrupt;
238 Handle threadA;
239 u32 threadA_stack[0x400];
240
threadA_entry(void *)241 void threadA_entry(void*) {
242 while (true) {
243 svcWaitSynchronization(dsp_interrupt, INT64_MAX);
244 ++interrupt_counter;
245 }
246 }
247
main()248 int main() {
249 aptInit();
250 gfxInitDefault();
251
252 consoleInit(GFX_TOP, &topScreen);
253 consoleInit(GFX_BOTTOM, &bottomScreen);
254
255 consoleSelect(&bottomScreen);
256 printf("Hello!\n");
257
258 UdpInit();
259
260 printf("dspInit: %08lX\n", dspInit());
261 bool loaded = false;
262 printf("DSP_LoadComponent: %08lX\n",
263 DSP_LoadComponent(cdc_bin, cdc_bin_size, 0xFF, 0xFF, &loaded));
264 printf("loaded = %d\n", loaded);
265
266 svcSleepThread(1000000000);
267 char hostname[100];
268 gethostname(hostname, 100);
269 printf("IP: %s port: 8888\n", hostname);
270
271 pmInit_();
272 printf("PM_TerminateTitle(DSP): %08lX\n", PM_TerminateTitle(0x0004013000001a02, 0));
273 pmExit_();
274
275 svcCreateEvent(&dsp_interrupt, ResetType::RESET_ONESHOT);
276 interrupt_counter = 0;
277 svcCreateThread(&threadA, threadA_entry, 0x0, threadA_stack + 0x400, 4, 0xFFFFFFFE);
278 printf("BindInterrupt: %08lX\n", svcBindInterrupt(0x4A, dsp_interrupt, 4, 0));
279
280 // Main loop
281 while (aptMainLoop()) {
282 hidScanInput();
283
284 u32 kDown = hidKeysDown();
285
286 if (kDown & KEY_START)
287 break;
288
289 if (kDown & KEY_A)
290 printf("hello\n");
291
292 CheckPackage();
293
294 PrintAll();
295
296 // Flush and swap framebuffers
297 gfxFlushBuffers();
298 gfxSwapBuffers();
299
300 // Wait for VBlank
301 gspWaitForVBlank();
302 }
303 socExit();
304 dspExit();
305 gfxExit();
306 aptExit();
307 return 0;
308 }
309