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