1 // Copyright (C) 2003 Dolphin Project.
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0.
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License 2.0 for more details.
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
15 // Official SVN repository and contact information can be found at
16 // http://code.google.com/p/dolphin-emu/
18 // This is a test program for running code on the Wii DSP, with full control over input
19 // and automatic compare with output. VERY useful for figuring out what those little
21 // It's very unpolished though
22 // Use Dolphin's dsptool to generate a new dsp_code.h.
23 // Originally written by duddie and modified by FIRES. Then further modified by ector.
38 #include <ogc/color.h>
39 #include <ogc/consol.h>
42 // Just for easy looking :)
43 #define HW_RVL //HW_DOL
47 #include <wiiuse/wpad.h>
48 #include <sdcard/wiisd_io.h>
51 #include "ConsoleHelper.h"
55 // This is where the DSP binary is.
59 // Communication with the real DSP and with the DSP emulator.
60 #include "dsp_interface.h"
62 // #include "virtual_dsp.h"
64 // Used for communications with the DSP, such as dumping registers etc.
65 u16 dspbuffer
[16 * 1024] __attribute__ ((aligned (0x4000)));
67 static void *xfb
= NULL
;
68 void (*reboot
)() = (void(*)())0x80001800;
71 static vu16
* const _dspReg
= (u16
*)0xCC005000;
78 0x0410, 0x0510, 0x0610, 0x0710, 0x0810, 0x0910, 0x0a10, 0x0b10,
79 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0855, 0x0966, 0x0a77, 0x0b88,
80 0x0014, 0xfff5, 0x00ff, 0x2200, 0x0000, 0x0000, 0x0000, 0x0000,
81 0x0003, 0x0004, 0x8000, 0x000C, 0x0007, 0x0008, 0x0009, 0x000a,
87 0x0e4c, 0x03c0, 0x0bd9, 0x06a3, 0x0c06, 0x0240, 0x0010, 0x0ecc,
88 0x0000, 0x0000, 0x0000, 0x0000, 0x0322, 0x0000, 0x0000, 0x0000,
89 0x0000, 0x0000, 0x00ff, 0x1b41, 0x0000, 0x0040, 0x00ff, 0x0000,
90 0x1000, 0x96cc, 0x0000, 0x0000, 0x3fc0, 0x96cc, 0x0000, 0x0000,
93 // if i set bit 0x4000 of SR my tests crashes :(
98 0x0a50, 0x0ca2, 0x04f8, 0x0ab0, 0x8039, 0x0000, 0x0000, 0x0000,
99 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x03d1, 0x0000, 0x0418, 0x0002, // r08 must have a value ... no idea why (ector: it's the looped addressing regs)
100 0x0000, 0x0000, 0x00ff, 0x1804, 0xdb70, 0x4ddb, 0x0000, 0x0000,
101 0x0000, 0x0000, 0x0000, 0xde6d, 0x0000, 0x0000, 0x0000, 0x004e,
104 u16 dspreg_out
[1000][32];
107 // gba ucode dmas result here
108 u32 SecParams_out[2] __attribute__ ((aligned (0x20))) = {
110 0x55667788 // bootinfo
114 u32 SecParams_in[8] __attribute__ ((aligned (0x20))) = {
115 0xDB967E0F, // key from gba
119 (u32)SecParams_out, //0x80075060, // ptr to receiving buffer
127 // UI (interactive register editing)
136 // Currently selected register.
138 // Currently selected digit.
140 // Value currently being edited.
145 // Currently running microcode
146 int curUcode
= 0, runningUcode
= 1;
151 // When comparing regs, ignore the loop stack registers.
152 bool regs_equal(int reg
, u16 value1
, u16 value2
)
154 if (reg
>= DSP_REG_ST0
&& reg
<= DSP_REG_ST3
)
157 return value1
== value2
;
160 void print_reg_block(int x
, int y
, int sel
, const u16
*regs
, const u16
*compare_regs
)
162 for (int j
= 0; j
< 4 ; j
++)
164 for (int i
= 0; i
< 8 ; i
++)
166 // Do not even display the loop stack registers.
167 const int reg
= j
* 8 + i
;
168 CON_SetColor(sel
== reg
? CON_BRIGHT_YELLOW
: CON_GREEN
);
169 CON_Printf(x
+ j
* 8, i
+ y
, "%02x ", reg
);
172 u8 color1
= regs_equal(reg
, regs
[reg
], compare_regs
[reg
]) ? CON_BRIGHT_WHITE
: CON_BRIGHT_RED
;
173 for (int k
= 0; k
< 4; k
++)
175 if (sel
== reg
&& k
== small_cursor_x
&& ui_mode
== UIM_EDIT_REG
)
176 CON_SetColor(CON_BRIGHT_CYAN
);
178 CON_SetColor(color1
);
179 CON_Printf(x
+ 3 + j
* 8 + k
, i
+ y
, "%01x", (regs
[reg
] >> ((3 - k
) * 4)) & 0xf);
184 CON_SetColor(CON_WHITE
);
186 CON_Printf(x
+2, y
+9, "ACC0: %02x %04x %04x", regs
[DSP_REG_ACH0
]&0xff, regs
[DSP_REG_ACM0
], regs
[DSP_REG_ACL0
]);
187 CON_Printf(x
+2, y
+10, "ACC1: %02x %04x %04x", regs
[DSP_REG_ACH1
]&0xff, regs
[DSP_REG_ACM1
], regs
[DSP_REG_ACL1
]);
188 CON_Printf(x
+2, y
+11, "AX0: %04x %04x", regs
[DSP_REG_AXH0
], regs
[DSP_REG_AXL0
]);
189 CON_Printf(x
+2, y
+12, "AX1: %04x %04x", regs
[DSP_REG_AXH1
], regs
[DSP_REG_AXL1
]);
192 void print_regs(int _step
, int _dsp_steps
)
194 const u16
*regs
= _step
== 0 ? dspreg_in
: dspreg_out
[_step
- 1];
195 const u16
*regs2
= dspreg_out
[_step
];
197 print_reg_block(0, 2, _step
== 0 ? cursor_reg
: -1, regs
, regs2
);
198 print_reg_block(33, 2, -1, regs2
, regs
);
200 CON_SetColor(CON_WHITE
);
201 CON_Printf(33, 17, "%i / %i ", _step
+ 1, _dsp_steps
);
205 static int count
= 0;
210 CON_SetColor(CON_WHITE
);
211 for (int i
= 0x0; i
< 0xf70 ; i
++)
213 if (dspbufC
[i
] != mem_dump
[i
])
215 CON_Printf(x
, y
, "%04x=%04x", i
, dspbufC
[i
]);
224 CON_Printf(4, 25, "%08x", count
);
227 void UpdateLastMessage(const char* msg
)
229 CON_PrintRow(4, 24, msg
);
232 void DumpDSP_ROMs(const u16
* rom
, const u16
* coef
)
235 char filename
[260] = {0};
236 sprintf(filename
, "sd:/dsp_rom.bin");
237 FILE *fROM
= fopen(filename
, "wb");
238 sprintf(filename
, "sd:/dsp_coef.bin");
239 FILE *fCOEF
= fopen(filename
, "wb");
242 fwrite(MEM_PHYSICAL_TO_K0(rom
), 0x2000, 1, fROM
);
245 fwrite(MEM_PHYSICAL_TO_K0(coef
), 0x1000, 1, fCOEF
);
247 UpdateLastMessage("DSP ROMs dumped to SD");
251 UpdateLastMessage("SD Write Error");
254 // Allow to connect to gdb (dump ram... :s)
259 void ui_pad_sel(void)
262 if (WPAD_ButtonsDown(0) & WPAD_BUTTON_RIGHT
)
264 if (WPAD_ButtonsDown(0) & WPAD_BUTTON_LEFT
)
266 if (WPAD_ButtonsDown(0) & WPAD_BUTTON_UP
)
268 if (WPAD_ButtonsDown(0) & WPAD_BUTTON_DOWN
)
271 if (WPAD_ButtonsDown(0) & WPAD_BUTTON_A
)
273 ui_mode
= UIM_EDIT_REG
;
274 reg_value
= &dspreg_in
[cursor_reg
];
277 if (PAD_ButtonsDown(0) & PAD_BUTTON_RIGHT
)
279 if (PAD_ButtonsDown(0) & PAD_BUTTON_LEFT
)
281 if (PAD_ButtonsDown(0) & PAD_BUTTON_UP
)
283 if (PAD_ButtonsDown(0) & PAD_BUTTON_DOWN
)
286 if (PAD_ButtonsDown(0) & PAD_BUTTON_A
)
288 ui_mode
= UIM_EDIT_REG
;
289 reg_value
= &dspreg_in
[cursor_reg
];
294 void ui_pad_edit_reg(void)
297 if (WPAD_ButtonsDown(0) & WPAD_BUTTON_RIGHT
)
299 if (WPAD_ButtonsDown(0) & WPAD_BUTTON_LEFT
)
301 small_cursor_x
&= 0x3;
303 if (WPAD_ButtonsDown(0) & WPAD_BUTTON_UP
)
304 *reg_value
+= 0x1 << (4 * (3 - small_cursor_x
));
305 if (WPAD_ButtonsDown(0) & WPAD_BUTTON_DOWN
)
306 *reg_value
-= 0x1 << (4 * (3 - small_cursor_x
));
307 if (WPAD_ButtonsDown(0) & WPAD_BUTTON_A
)
309 if (WPAD_ButtonsDown(0) & WPAD_BUTTON_1
)
311 if (WPAD_ButtonsDown(0) & WPAD_BUTTON_2
)
314 if (PAD_ButtonsDown(0) & PAD_BUTTON_RIGHT
)
316 if (PAD_ButtonsDown(0) & PAD_BUTTON_LEFT
)
318 small_cursor_x
&= 0x3;
320 if (PAD_ButtonsDown(0) & PAD_BUTTON_UP
)
321 *reg_value
+= 0x1 << (4 * (3 - small_cursor_x
));
322 if (PAD_ButtonsDown(0) & PAD_BUTTON_DOWN
)
323 *reg_value
-= 0x1 << (4 * (3 - small_cursor_x
));
324 if (PAD_ButtonsDown(0) & PAD_BUTTON_A
)
326 if (PAD_ButtonsDown(0) & PAD_BUTTON_X
)
328 if (PAD_ButtonsDown(0) & PAD_BUTTON_Y
)
333 void handle_dsp_mail(void)
335 // Should put a loop around this too.
336 if (DSP_CheckMailFrom())
338 u32 mail
= DSP_ReadMailFrom();
340 if (mail
== 0x8071feed)
342 // DSP ready for task. Let's send one.
343 // First, prepare data.
344 for (int n
= 0 ; n
< 32 ; n
++)
345 dspbufC
[0x00 + n
] = dspreg_in
[n
];
346 DCFlushRange(dspbufC
, 0x2000);
347 // Then send the code.
348 DCFlushRange((void *)dsp_code
[curUcode
], 0x2000);
349 // DMA ucode to iram base, entry point is just after exception vectors...0x10
350 // NOTE: for any ucode made by dsptool, the block length will be 8191
351 real_dsp
.SendTask((void *)MEM_VIRTUAL_TO_PHYSICAL(dsp_code
[curUcode
]), 0, sizeof(dsp_code
[curUcode
])-1, 0x10);
353 runningUcode
= curUcode
+ 1;
355 // Clear exception status since we've loaded a new ucode
358 else if ((mail
& 0xffff0000) == 0x8bad0000)
360 // dsp_base.inc is reporting an exception happened
361 CON_PrintRow(4, 25, "%s caused exception %x at step %i", UCODE_NAMES
[curUcode
], mail
& 0xff, dsp_steps
);
363 else if (mail
== 0x8888dead)
365 // Send memory dump (dsp dram from someone's cube?)
366 // not really sure why this is important - I guess just to try to keep tests predictable
367 u16
* tmpBuf
= (u16
*)MEM_VIRTUAL_TO_PHYSICAL(mem_dump
);
369 while (real_dsp
.CheckMailTo());
370 real_dsp
.SendMailTo((u32
)tmpBuf
);
371 while (real_dsp
.CheckMailTo());
373 else if (mail
== 0x8888beef)
375 // Provide register base to dsp (if using dsp_base.inc, it will dma them to the correct place)
376 while (real_dsp
.CheckMailTo());
377 real_dsp
.SendMailTo((u32
)dspbufP
);
378 while (real_dsp
.CheckMailTo());
380 else if (mail
== 0x8888feeb)
382 // We got a stepful of registers.
383 DCInvalidateRange(dspbufC
, 0x2000);
384 for (int i
= 0 ; i
< 32 ; i
++)
385 dspreg_out
[dsp_steps
][i
] = dspbufC
[0xf80 + i
];
389 while (real_dsp
.CheckMailTo());
390 real_dsp
.SendMailTo(0x8000dead);
391 while (real_dsp
.CheckMailTo());
395 else if (mail
== 0x8888c0de)
397 // DSP has copied irom to its dram...send address so it can dma it back
398 while (real_dsp
.CheckMailTo());
399 real_dsp
.SendMailTo((u32
)dspbufP
);
400 while (real_dsp
.CheckMailTo());
402 else if (mail
== 0x8888da7a)
404 // DSP has copied coef to its dram...send address so it can dma it back
405 while (real_dsp
.CheckMailTo());
406 real_dsp
.SendMailTo((u32
)&dspbufP
[0x1000]);
407 while (real_dsp
.CheckMailTo());
409 // Now we can do something useful with the buffer :)
410 DumpDSP_ROMs(dspbufP
, &dspbufP
[0x1000]);
416 else if (mail == 0xdcd10000) // DSP_INIT
418 real_dsp.SendMailTo(0xabba0000);
419 while (real_dsp.CheckMailTo());
420 DCFlushRange(SecParams_in, sizeof(SecParams_in));
421 CON_PrintRow(4, 25, "SecParams_out = %x", SecParams_in[4]);
422 real_dsp.SendMailTo((u32)SecParams_in);
423 while (real_dsp.CheckMailTo());
425 else if (mail == 0xdcd10003) // DSP_DONE
427 real_dsp.SendMailTo(0xcdd1babe); // custom mail to tell dsp to halt (calls end_of_test)
428 while (real_dsp.CheckMailTo());
430 DCInvalidateRange(SecParams_out, sizeof(SecParams_out));
431 CON_PrintRow(4, 26, "SecParams_out: %08x %08x",
432 SecParams_out[0], SecParams_out[1]);
436 CON_PrintRow(2, 1, "UCode: %d/%d %s, Last mail: %08x",
437 curUcode
+ 1, NUM_UCODES
, UCODE_NAMES
[curUcode
], mail
);
441 void dump_all_ucodes(bool fastmode
)
443 char filename
[260] = {0};
447 sprintf(filename
, "sd:/dsp_dump_all.bin");
448 FILE *f2
= fopen(filename
, "wb");
451 for (int UCodeToDump
= 0; UCodeToDump
< NUM_UCODES
; UCodeToDump
++)
453 // First, change the microcode
455 curUcode
= UCodeToDump
;
458 DCInvalidateRange(dspbufC
, 0x2000);
459 DCFlushRange(dspbufC
, 0x2000);
464 // Loop over handling mail until we've stopped stepping
465 // dsp_steps-3 compensates for mails to setup the ucode
466 for (int steps_cache
= dsp_steps
-3; steps_cache
<= dsp_steps
; steps_cache
++)
470 sprintf(filename
, "sd:/dsp_dump_all.bin");
471 FILE *f2
= fopen(filename
, "ab");
473 if (fastmode
== false)
475 // Then write microcode dump to file
476 sprintf(filename
, "sd:/dsp_dump%d.bin", UCodeToDump
);
477 FILE *f
= fopen(filename
, "wb");
480 // First write initial regs
481 written
= fwrite(dspreg_in
, 1, 32 * 2, f
);
483 // Then write all the dumps.
484 written
+= fwrite(dspreg_out
, 1, dsp_steps
* 32 * 2, f
);
489 UpdateLastMessage("SD Write Error");
494 if (f2
) //all in 1 dump file (extra)
496 if (UCodeToDump
== 0) {
497 // First write initial regs
498 written
= fwrite(dspreg_in
, 1, 32 * 2, f2
);
499 written
+= fwrite(dspreg_out
, 1, dsp_steps
* 32 * 2, f2
);
502 written
= fwrite(dspreg_out
, 1, dsp_steps
* 32 * 2, f2
);
507 if (UCodeToDump
< NUM_UCODES
-1)
509 sprintf(temp
, "Dump %d Successful. Wrote %d bytes, steps: %d", UCodeToDump
+1, written
, dsp_steps
);
510 UpdateLastMessage(temp
);
513 UpdateLastMessage("DUMPING DONE!");
518 UpdateLastMessage("SD Write Error");
524 // Shove common, un-dsp-ish init things here
527 // Initialize the video system
530 // This function initializes the attached controllers
536 // Obtain the preferred video mode from the system
537 // This will correspond to the settings in the Wii menu
538 rmode
= VIDEO_GetPreferredMode(NULL
);
540 // Allocate memory for the display in the uncached region
541 xfb
= MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode
));
543 // Set up the video registers with the chosen mode
544 VIDEO_Configure(rmode
);
545 // Tell the video hardware where our display memory is
546 VIDEO_SetNextFramebuffer(xfb
);
547 // Make the display visible
548 VIDEO_SetBlack(FALSE
);
549 // Flush the video register changes to the hardware
551 // Wait for Video setup to complete
553 if (rmode
->viTVMode
& VI_NON_INTERLACE
)
556 // Initialize the console, required for printf
557 CON_Init(xfb
, 20, 64, rmode
->fbWidth
, rmode
->xfbHeight
, rmode
->fbWidth
* VI_DISPLAY_PIX_SZ
);
560 // Initialize FAT so we can write to SD.
561 __io_wiisd
.startup();
562 fatMountSimple("sd", &__io_wiisd
);
564 // Init debug over BBA...change IPs to suite your needs
565 tcp_localip
="192.168.1.103";
566 tcp_netmask
="255.255.255.0";
567 tcp_gateway
="192.168.1.2";
568 DEBUG_Init(GDBSTUB_DEVICE_TCP
, GDBSTUB_DEF_TCPPORT
);
576 __io_wiisd
.shutdown();
579 UpdateLastMessage("Exiting...");
590 dspbufP
= (u16
*)MEM_VIRTUAL_TO_PHYSICAL(dspbuffer
); // physical
591 dspbufC
= dspbuffer
; // cached
592 dspbufU
= (u32
*)(MEM_K0_TO_K1(dspbuffer
)); // uncached
594 DCInvalidateRange(dspbuffer
, 0x2000);
595 for (int j
= 0; j
< 0x800; j
++)
596 dspbufU
[j
] = 0xffffffff;
610 if (PAD_ButtonsDown(0) & PAD_BUTTON_START
)
614 if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME
)
617 CON_Printf(2, 18, "Controls:");
618 CON_Printf(4, 19, "+/- (GC:'L'/'R') to move");
619 CON_Printf(4, 20, "A (GC:'A') to edit register; B (GC:'B') to start over");
620 CON_Printf(4, 21, "1 (GC:'Z') to move next microcode");
621 CON_Printf(4, 22, "2 (GC:'X') dump results to SD; UP (GC:'Y') dump results to SD (SINGLE FILE)");
622 CON_Printf(4, 23, "Home (GC:'START') to exit");
624 CON_Printf(2, 18, "Controls:");
625 CON_Printf(4, 19, "L/R to move");
626 CON_Printf(4, 20, "A to edit register, B to start over");
627 CON_Printf(4, 21, "Z to move to next microcode");
628 CON_Printf(4, 22, "Start to exit");
631 print_regs(show_step
, dsp_steps
);
642 // ui_pad_edit_bin();
647 DCFlushRange(xfb
, 0x200000);
650 // Use B to start over.
652 if ((WPAD_ButtonsDown(0) & WPAD_BUTTON_B
) || (PAD_ButtonsDown(0) & PAD_BUTTON_B
))
654 if (PAD_ButtonsDown(0) & PAD_BUTTON_B
)
657 dsp_steps
= 0; // Let's not add the new steps after the original ones. That was just annoying.
659 DCInvalidateRange(dspbufC
, 0x2000);
660 DCFlushRange(dspbufC
, 0x2000);
664 UpdateLastMessage("OK");
667 // Navigate between results using + and - buttons.
669 if ((WPAD_ButtonsDown(0) & WPAD_BUTTON_PLUS
) || (PAD_ButtonsDown(0) & PAD_TRIGGER_R
))
671 if (PAD_ButtonsDown(0) & PAD_TRIGGER_R
)
675 if (show_step
>= dsp_steps
)
677 UpdateLastMessage("OK");
680 if ((WPAD_ButtonsDown(0) & WPAD_BUTTON_MINUS
) || (PAD_ButtonsDown(0) & PAD_TRIGGER_L
))
682 if (PAD_ButtonsDown(0) & PAD_TRIGGER_L
)
687 show_step
= dsp_steps
- 1;
688 UpdateLastMessage("OK");
692 if ((WPAD_ButtonsDown(0) & WPAD_BUTTON_1
) || (PAD_ButtonsDown(0) & PAD_TRIGGER_Z
))
694 if (PAD_ButtonsDown(0) & PAD_TRIGGER_Z
)
698 if(curUcode
== NUM_UCODES
)
701 // Reset step counters since we're in a new ucode.
705 DCInvalidateRange(dspbufC
, 0x2000);
706 for (int n
= 0 ; n
< 0x2000 ; n
++)
708 // dspbufU[n/2] = 0; dspbufC[n] = 0;
710 DCFlushRange(dspbufC
, 0x2000);
714 UpdateLastMessage("OK");
716 // Waiting for video to synchronize (enough time to set our new microcode)
721 // Probably could offer to save to sd gecko or something on gc...
722 // The future is web-based reporting ;)
723 if ((WPAD_ButtonsDown(0) & WPAD_BUTTON_2
) || (PAD_ButtonsDown(0) & PAD_BUTTON_X
))
725 dump_all_ucodes(false);
728 // Dump all results into 1 file (skip file per ucode part) = FAST because of LIBFAT filecreate bug
729 if ((WPAD_ButtonsDown(0) & WPAD_BUTTON_UP
) || (PAD_ButtonsDown(0) & PAD_BUTTON_Y
))
731 dump_all_ucodes(true);
739 // Will never reach here, but just to be sure..