gbdk-2020 | GameBoy Development Kit |
| download: https://git.y1.nz/archives/gbdk.tar.gz | |
| README | Files | Log | Refs | LICENSE |
gbdk-lib/examples/cross-platform/emu_debug/src/emu_debug.c
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
26 int 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 // Note how the register value is obtained by using parenthesis to de-referenced its address.
136 // (Current Y coordinate being rendered to the LCD)
137 EMU_MESSAGE("LY Register (0xFF44): %($ff44)%");
138 EMU_MESSAGE("LY Register (0xFF44): %($ff44)%");
139 // Now print a conditional debug message using it
140 EMU_MESSAGE("Is LY Register > Line 67: %($ff44)>67%Yes;No;");
141 #endif
142
143 int16_t var_s16 = -1234;
144 uint16_t var_u16 = 31002;
145 uint16_t var_u16h = 0xA50Fu;
146 int8_t var_s8 = -56;
147 uint8_t var_u8 = 224;
148 uint8_t var_u8h = 0xF8;
149 char var_chr = 'A';
150 char * var_string = "Hello Emu Printf";
151
152 // For EMU_printf:
153 // Note how all the 8 bit arguments must be explicitly cast EXCEPT for %c
154 // In partifcular, %c MUST NOT be cast or the output will be incorrect
155 EMU_printf("signed int: %d\n"
156 "unsigned int: %u\n"
157 "hex int: 0x%X\n"
158 "signed byte: %hd\n"
159 "unsigned byte: %hu\n"
160 "hex byte: 0x%hX\n"
161 "Character: %c\n"
162 "String: %s\n",
163 (int16_t) var_s16,
164 (uint16_t) var_u16,
165 (uint16_t) var_u16h,
166 (int8_t)var_s8,
167 (uint8_t)var_u8,
168 (uint8_t)var_u8h,
169 var_chr, // Do not explicitly cast %c vars for EMU_printf, it expects them auto-promoted to 2 bytes (casting would prevent that)
170 var_string);
171
172 // The EMU_TEXT() macro will accept a non-quoted string
173 EMU_TEXT("The End");
174
175 return 0;
176 }
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.