Files
gbdk-2020/gbdk-lib/include/gbdk/emu_debug.h

184 lines
5.7 KiB
C

/** @file gbdk/emu_debug.h
Debug window logging and profiling support for emulators (BGB, Emulicious, etc).
Also see the `emu_debug` example project included with gbdk.
See the BGB Manual for more information
("expressions, breakpoint conditions, and debug messages")
http://bgb.bircd.org/manual.html#expressions
*/
// Suppress SDCC "info 128" warnings that are a non-issue
#pragma disable_warning 218
#ifndef __GBDK_EMU_DEBUG_H_INCLUDE
#define __GBDK_EMU_DEBUG_H_INCLUDE
#include <types.h>
#if defined(__TARGET_gb) || defined(__TARGET_duck) || defined(__TARGET_ap) || defined(__TARGET_sms) || defined(__TARGET_gg)
/** Macro to display a message in the emulator debug message window
@param message_text Quoted text string to display in the debug message window
The following special parameters can be
used when bracketed with "%" characters.
\li CPU registers: AF, BC, DE, HL, SP, PC, B, C, D,
E, H, L, A, ZERO, ZF, Z, CARRY, CY, IME, ALLREGS
\li Other state values: ROMBANK, XRAMBANK, SRAMBANK,
WRAMBANK, VRAMBANK, TOTALCLKS, LASTCLKS, CLKS2VBLANK
Example: print a message along with the currently active ROM bank.
\code{.c}
EMU_MESSAGE("Current ROM Bank is: %ROMBANK%");
\endcode
See the BGB Manual for more information
("expressions, breakpoint conditions, and debug messages")
http://bgb.bircd.org/manual.html#expressions
@see EMU_PROFILE_BEGIN(), EMU_PROFILE_END()
*/
#define EMU_MESSAGE(message_text) EMU_MESSAGE1(EMU_MACRONAME(__LINE__), message_text)
#define BGB_MESSAGE(message_text) EMU_MESSAGE(message_text)
/// \cond DOXYGEN_DO_NOT_DOCUMENT
#define EMU_MACRONAME(A) EMU_MACRONAME1(A)
#define EMU_MACRONAME1(A) EMULOG##A
#define EMU_MESSAGE1(name, message_text) \
__asm \
.MACRO name msg_t, ?llbl \
ld d, d \
jr llbl \
.dw 0x6464 \
.dw 0x0000 \
.ascii msg_t \
llbl: \
.ENDM \
name ^/message_text/ \
__endasm
#define EMU_MESSAGE_SUFFIX(message_text, message_suffix) EMU_MESSAGE3(EMU_MACRONAME(__LINE__), message_text, message_suffix)
#define EMU_MESSAGE3(name, message_text, message_suffix) \
__asm \
.MACRO name msg_t, msg_s, ?llbl \
ld d, d \
jr llbl \
.dw 0x6464 \
.dw 0x0000 \
.ascii msg_t \
.ascii msg_s \
llbl: \
.ENDM \
name ^/message_text/, ^/message_suffix/ \
__endasm
/// \endcond DOXYGEN_DO_NOT_DOCUMENT
/** Macro to __Start__ a profiling block for the emulator (BGB, Emulicious, etc)
@param MSG Quoted text string to display in the
debug message window along with the result
To complete the profiling block and print
the result call @ref EMU_PROFILE_END.
@see EMU_PROFILE_END(), EMU_MESSAGE()
*/
#define EMU_PROFILE_BEGIN(MSG) EMU_MESSAGE_SUFFIX(MSG, "%ZEROCLKS%");
#define BGB_PROFILE_BEGIN(MSG) EMU_PROFILE_BEGIN(MSG)
/** Macro to __End__ a profiling block and print the results in the emulator debug message window
@param MSG Quoted text string to display in the
debug message window along with the result
This should only be called after a previous call
to @ref EMU_PROFILE_BEGIN()
The results are in Emulator clock units, which are
"1 nop in [CGB] doublespeed mode".
So when running in Normal Speed mode (i.e. non-CGB doublespeed)
the printed result should be __divided by 2__ to get the actual
ellapsed cycle count.
If running in CB Double Speed mode use the below call instead,
it correctly compensates for the speed difference. In this
scenario, the result does __not need to be divided by 2__ to
get the ellapsed cycle count.
\code{.c}
EMU_MESSAGE("NOP TIME: %-4+LASTCLKS%");
\endcode
@see EMU_PROFILE_BEGIN(), EMU_MESSAGE()
*/
#if defined(NINTENDO)
#define EMU_PROFILE_END(MSG) EMU_MESSAGE_SUFFIX(MSG,"%-8+LASTCLKS%");
#define BGB_PROFILE_END(MSG) EMU_PROFILE_END(MSG)
#elif defined(SEGA)
#define EMU_PROFILE_END(MSG) EMU_MESSAGE_SUFFIX(MSG,"%-16+LASTCLKS%");
#define BGB_PROFILE_END(MSG) EMU_PROFILE_END(MSG)
#endif
#define EMU_TEXT(MSG) EMU_MESSAGE(MSG)
#define BGB_TEXT(MSG) EMU_TEXT(MSG)
/** Print the string and arguments given by format to the emulator debug message window
@param format The format string as per printf
Does not return the number of characters printed.
Currently supported:
\li \%hx (char as hex)
\li \%hu (unsigned char)
\li \%hd (signed char)
\li \%c (character)
\li \%u (unsigned int)
\li \%d (signed int)
\li \%x (unsigned int as hex)
\li \%s (string)
@note
Variables for the following 8-bit formats __MUST__ be cast to their type when passed to EMU_printf()
\li \%hx (char)
\li \%hu (unsigned char)
\li \%hd (signed char)
However variables for the following 8-bit format __MUST NOT__ be cast to their type when passed to EMU_printf()
\li \%c (char)
This behavior is __different__ than for @ref sprintf(), which does require \%c format char variables to be explicitly cast.
Currently supported in the Emulicious emulator, may be supported by bgb
*/
void EMU_printf(const char *format, ...) PRESERVES_REGS(a, b, c);
#define BGB_printf(...) EMU_printf(__VA_ARGS__)
/** Print the string and arguments in the buffer buffer by the pointer given by format to the emulator debug message window
@param format The format string as per printf
@param data Buffer containing arguments, for example some struct
@see EMU_printf for the format string description
Currently supported in the Emulicious emulator
*/
void EMU_fmtbuf(const unsigned char * format, void * data) PRESERVES_REGS(a, b, c);
/** The Emulator will break into debugger when encounters this line
*/
#define EMU_BREAKPOINT __asm__("ld b, b");
#define BGB_BREAKPOINT EMU_BREAKPOINT
#else
#error Unrecognized port
#endif
#endif