emu_debug.c (5911B)
1#include <gbdk/platform.h> 2#include <stdint.h> 3#include <stdio.h> // Just for printf() 4 5#include <gbdk/emu_debug.h> // Use this include to add the Emu debug functions 6 7 8// This example shows how to use support for profiling 9// and logging to the debug window in the emulator (BGB or Emulicious). 10// 11// 1. Build this ROM (emu_debug.gb) then load it in the emulator (BGB or Emulicious) 12// 2. Open the internal debugger by pressing the "ESC" or "F1" key 13// 3. From the debugger menu choose "debug messages" to open the debug messages window 14// 4. Reset the gameboy (you may need to press F9 in the debugger to resume running) 15// 5. The debug window will show the debug messages 16// 17// See the BGB Manual for more information 18// ("expressions, breakpoint conditions, and debug messages") 19// https://bgb.bircd.org/manual.html#expressions 20 21// If you see a message like the following, it is safe to ignore. It is a known 22// issue with SDCC and should not cause problems. 23// 24// " src/emu_debug.c:156: info 218: z80instructionSize() failed to parse line node, assuming 999 bytes ' llbl:' 25 26int main(void) 27{ 28 SHOW_BKG; 29 DISPLAY_ON; 30 31 // Display a message on the screen 32 printf("Message to the\nScreen\n"); 33 34 // Log a message to the Emulator debug message window 35 EMU_MESSAGE(""); // new line 36 EMU_MESSAGE("Message to the EMU console"); 37 38 // ==== Normal Speed Mode ==== 39 // Profile code: a single NOP instruction 40 // 41 // The clock units are "1 nop in [CGB] doublespeed mode". 42 // So when *not* running in CGB doublespeed mode you 43 // have to divide by 2 to get the correct cycle count. 44 // 45 // You should see the message "NOP TIME: 2". 46 // 47 // So in this case, divide the printed value by 2 = The NOP took "1" cycle 48 49 __critical { // Temporarily turn off interrupts for more accurate measurements 50 EMU_PROFILE_BEGIN("Profile a single NOP instruction at Normal Speed"); 51 __asm__("nop"); 52 EMU_PROFILE_END("NOP TIME:"); 53 } 54 55 56 #ifdef NINTENDO 57 // ==== Color Game Boy in Double Speed Mode ==== 58 // Profile code: a single NOP instruction 59 // 60 // The EMU_PROFILE_BEGIN/END macros don't support the 61 // Color Game Boy (CGB) in double speed mode (cpu_fast()). 62 // The example below shows what to use instead (and how to 63 // check for a CGB and turn on Double Speed mode). 64 // 65 // Check and only run this test if on CGB hardware 66 if (DEVICE_SUPPORTS_COLOR) { 67 68 // Set CGB into double speed mode 69 // (Requires passing -Wm-yc or -Wm-yC with Lcc during build time) 70 cpu_fast(); 71 // Set some default DMG styled colors in the CGB Palette 72 set_default_palette(); 73 74 // In CGB Double Speed mode, you don't have to 75 // divide by 2 to get the cycle count. 76 // 77 // You should see the message "NOP TIME: 1". 78 79 __critical { // Temporarily turn off interrupts for more accurate measurements 80 EMU_PROFILE_BEGIN("Profile a single NOP instruction at CGB Double Speed"); 81 __asm__("nop"); 82 // The "-4+" subtracts 4 clocks to compensate for the ones 83 // used by the debug message itself (Normal speed uses -8) 84 EMU_MESSAGE("NOP TIME:%-4+LASTCLKS%"); 85 } 86 87 // Return the CGB to normal speed 88 cpu_slow(); 89 } 90 #endif // NINTENDO 91 92 93 __critical { // Temporarily turn off interrupts for more accurate measurements 94 95 int c; 96 97 // Profile code in a loop 98 EMU_PROFILE_BEGIN("Profile code in a loop"); 99 for(c=0; c<5; c++) { 100 // Do something 101 printf("%d\n", c); 102 } 103 // Elapsed cycle count output is in hex. 104 // Remember to divide by 2 for the result (Normal Speed) 105 EMU_PROFILE_END("LOOP TIME:"); 106 } 107 108 // ==== Some other things you can print ==== 109 110 // - For Game Boy TOTALCLKS shows the clocks counter ("internal divider") 111 // - For SMS/GG TOTALCLKS is relative to CLKS2VBLANK (so at most it can be the max clocks to vblank) 112 EMU_MESSAGE("Total Clocks: %TOTALCLKS%"); 113 114 // CLKS2VBLANK 115 EMU_MESSAGE("Clocks until VBLANK: %CLKS2VBLANK%"); 116 117 // Which Banks are currently active (for MBC based cartridges) 118 EMU_MESSAGE("Current ROM bank: %ROMBANK%"); 119 EMU_MESSAGE("Current SRAM bank: %SRAMBANK%"); 120 // These are not banked on DMG/MGB Game Boys 121 EMU_MESSAGE("Current VRAM bank: %VRAMBANK%"); 122 EMU_MESSAGE("Current WRAM bank: %WRAMBANK%"); 123 124 // Registers (All in this case, or individual ones) 125 EMU_MESSAGE("All Registers: %ALLREGS%"); 126 127 // Simple addition with a register 128 EMU_MESSAGE("Register A + 1: %(A+1)%"); 129 130 // Note: %SCANLINE% is available in Emulicious (for SMS/GG/GB/GBC) but not BGB 131 EMU_MESSAGE("Current Scanline: %SCANLINE%"); 132 133 #if defined(NINTENDO) 134 // Read the LY Register a couple times 135 // (Current Y coordinate being rendered to the LCD) 136 EMU_MESSAGE("LY Register (0xFF44): %($ff44)%"); 137 EMU_MESSAGE("LY Register (0xFF44): %($ff44)%"); 138 // Now print a conditional debug message using it 139 EMU_MESSAGE("Is LY Register > Line 67: %($ff44)>67%Yes;No;"); 140 #endif 141 142 143 #if defined(NINTENDO) 144 // Print some profile info using a built-in function. 145 EMU_MESSAGE("The following lines contain: PROFILE,(SP+$0),(SP+$1),A,TOTALCLKS,ROMBANK,WRAMBANK"); 146 147 EMU_profiler_message(); 148 149 // It's equivalent to: 150 EMU_MESSAGE("PROFILE,%(SP+$0)%,%(SP+$1)%,%A%,%TOTALCLKS%,%ROMBANK%,%WRAMBANK%"); 151 152 #elif defined(SEGA) 153 EMU_MESSAGE("PROFILE,%(SP+$0)%,%(SP+$1)%,%A%,%TOTALCLKS%,%ROMBANK%,%WRAMBANK%"); 154 #endif 155 156 uint8_t var0 = 16; 157 int16_t var1 = -10; 158 EMU_printf("var0: %hd; var1: %d; var0*var1=%d", (uint8_t)var0, var1, var0 * var1); 159 160 // The EMU_TEXT() macro will accept a non-quoted string 161 EMU_TEXT("The End"); 162 163 return 0; 164}