git.y1.nz

gbdk-2020

GameBoy Development Kit
download: https://git.y1.nz/archives/gbdk.tar.gz
README | Files | Log | Refs | LICENSE

commit 37488731bae42837d41a38adae571e05b0ff96e7
parent a03be6fad80edde64a4730198ebd11360eb85c89
Author: bbbbbr <bbbbbr@users.noreply.github.com>
Date:   Tue,  1 Mar 2022 13:20:21 -0800

Merge pull request #326 from bbbbbr/feature_sms_gg_emudebug

Initial Emu debug console support for sms/gg
Diffstat:
Agbdk-lib/examples/cross-platform/emu_debug/Makefile78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Agbdk-lib/examples/cross-platform/emu_debug/Makefile.targets50++++++++++++++++++++++++++++++++++++++++++++++++++
Agbdk-lib/examples/cross-platform/emu_debug/src/emu_debug.c158+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dgbdk-lib/examples/gb/emu_debug/Makefile17-----------------
Dgbdk-lib/examples/gb/emu_debug/emu_debug.c147-------------------------------------------------------------------------------
Mgbdk-lib/include/gb/emu_debug.h11++++++++++-
Agbdk-lib/include/gbdk/emu_debug.h13+++++++++++++
Agbdk-lib/libc/targets/z80/emu_debug_printf.s44++++++++++++++++++++++++++++++++++++++++++++
Mgbdk-lib/libc/targets/z80/gg/Makefile1+
Mgbdk-lib/libc/targets/z80/sms/Makefile1+
10 files changed, 355 insertions(+), 165 deletions(-)

diff --git a/gbdk-lib/examples/cross-platform/emu_debug/Makefile b/gbdk-lib/examples/cross-platform/emu_debug/Makefile @@ -0,0 +1,78 @@ +# If you move this project you can change the directory +# to match your GBDK root directory (ex: GBDK_HOME = "C:/GBDK/" +GBDK_HOME = ../../../ +LCC = $(GBDK_HOME)bin/lcc + +# Set platforms to build here, spaced separated. (These are in the separate Makefile.targets) +# They can also be built/cleaned individually: "make gg" and "make gg-clean" +# Possible are: gb gbc pocket megaduck sms gg +TARGETS=gg gbc + +# Configure platform specific LCC flags here: +LCCFLAGS_gb = -Wl-yt0x1B # Set an MBC for banking (1B-ROM+MBC5+RAM+BATT) +LCCFLAGS_pocket = -Wl-yt0x1B # Usually the same as required for .gb +LCCFLAGS_duck = -Wl-yt0x1B # Usually the same as required for .gb +LCCFLAGS_gbc = -Wl-yt0x1B -Wm-yc # Same as .gb with: -Wm-yc (gb & gbc) or Wm-yC (gbc exclusive) +LCCFLAGS_sms = +LCCFLAGS_gg = + +LCCFLAGS += $(LCCFLAGS_$(EXT)) # This adds the current platform specific LCC Flags + +LCCFLAGS += -Wl-j -Wm-yoA -Wm-ya4 -autobank -Wb-ext=.rel -Wb-v # MBC + Autobanking related flags +LCCFLAGS += -debug # Uncomment to enable debug output +# LCCFLAGS += -v # Uncomment for lcc verbose output + +# You can set the name of the ROM file here +PROJECTNAME = emu_debug + +# EXT?=gb # Only sets extension to default (game boy .gb) if not populated +SRCDIR = src +OBJDIR = obj/$(EXT) +RESDIR = res +BINDIR = build/$(EXT) +MKDIRS = $(OBJDIR) $(BINDIR) # See bottom of Makefile for directory auto-creation + +BINS = $(OBJDIR)/$(PROJECTNAME).$(EXT) +CSOURCES = $(foreach dir,$(SRCDIR),$(notdir $(wildcard $(dir)/*.c))) $(foreach dir,$(RESDIR),$(notdir $(wildcard $(dir)/*.c))) +ASMSOURCES = $(foreach dir,$(SRCDIR),$(notdir $(wildcard $(dir)/*.s))) +OBJS = $(CSOURCES:%.c=$(OBJDIR)/%.o) $(ASMSOURCES:%.s=$(OBJDIR)/%.o) + +# Builds all targets sequentially +all: $(TARGETS) + +# Compile .c files in "src/" to .o object files +$(OBJDIR)/%.o: $(SRCDIR)/%.c + $(LCC) $(CFLAGS) -c -o $@ $< + +# Compile .c files in "res/" to .o object files +$(OBJDIR)/%.o: $(RESDIR)/%.c + $(LCC) $(CFLAGS) -c -o $@ $< + +# Compile .s assembly files in "src/" to .o object files +$(OBJDIR)/%.o: $(SRCDIR)/%.s + $(LCC) $(CFLAGS) -c -o $@ $< + +# If needed, compile .c files i n"src/" to .s assembly files +# (not required if .c is compiled directly to .o) +$(OBJDIR)/%.s: $(SRCDIR)/%.c + $(LCC) $(CFLAGS) -S -o $@ $< + +# Link the compiled object files into a .gb ROM file +$(BINS): $(OBJS) + $(LCC) $(LCCFLAGS) $(CFLAGS) -o $(BINDIR)/$(PROJECTNAME).$(EXT) $(OBJS) + +clean: + @echo Cleaning + @for target in $(TARGETS); do \ + $(MAKE) $$target-clean; \ + done + +# Include available build targets +include Makefile.targets + + +# create necessary directories after Makefile is parsed but before build +# info prevents the command from being pasted into the makefile +ifneq ($(strip $(EXT)),) # Only make the directories if EXT has been set by a target +$(info $(shell mkdir -p $(MKDIRS))) +endif diff --git a/gbdk-lib/examples/cross-platform/emu_debug/Makefile.targets b/gbdk-lib/examples/cross-platform/emu_debug/Makefile.targets @@ -0,0 +1,50 @@ + +# Platform specific flags for compiling (only populate if they're both present) +ifneq ($(strip $(PORT)),) +ifneq ($(strip $(PLAT)),) +CFLAGS += -m$(PORT):$(PLAT) +endif +endif + +# Called by the individual targets below to build a ROM +build-target: $(BINS) + +clean-target: + rm -rf $(OBJDIR) + rm -rf $(BINDIR) + +gb-clean: + ${MAKE} clean-target EXT=gb +gb: + ${MAKE} build-target PORT=gbz80 PLAT=gb EXT=gb + + +gbc-clean: + ${MAKE} clean-target EXT=gbc +gbc: + ${MAKE} build-target PORT=gbz80 PLAT=gb EXT=gbc + + +pocket-clean: + ${MAKE} clean-target EXT=pocket +pocket: + ${MAKE} build-target PORT=gbz80 PLAT=ap EXT=pocket + + +megaduck-clean: + ${MAKE} clean-target EXT=duck +megaduck: + ${MAKE} build-target PORT=gbz80 PLAT=duck EXT=duck + + +sms-clean: + ${MAKE} clean-target EXT=sms +sms: + ${MAKE} build-target PORT=z80 PLAT=sms EXT=sms + + +gg-clean: + ${MAKE} clean-target EXT=gg +gg: + ${MAKE} build-target PORT=z80 PLAT=gg EXT=gg + diff --git a/gbdk-lib/examples/cross-platform/emu_debug/src/emu_debug.c b/gbdk-lib/examples/cross-platform/emu_debug/src/emu_debug.c @@ -0,0 +1,158 @@ +#include <gbdk/platform.h> +#include <stdint.h> +#include <stdio.h> // Just for printf() + +#include <gbdk/emu_debug.h> // Use this include to add the Emu debug functions + + +// This example shows how to use support for profiling +// and logging to the debug window in the emulator (BGB or Emulicious). +// +// 1. Build this ROM (emu_debug.gb) then load it in the emulator (BGB or Emulicious) +// 2. Open the internal debugger by pressing the "ESC" or "F1" key +// 3. From the debugger menu choose "debug messages" to open the debug messages window +// 4. Reset the gameboy (you may need to press F9 in the debugger to resume running) +// 5. The debug window will show the debug messages +// +// See the BGB Manual for more information +// ("expressions, breakpoint conditions, and debug messages") +// https://bgb.bircd.org/manual.html#expressions + +int main(void) +{ + SHOW_BKG; + DISPLAY_ON; + + // Display a message on the screen + printf("Message to the\nScreen\n"); + + // Log a message to the Emulator debug message window + EMU_MESSAGE(""); // new line + EMU_MESSAGE("Message to the EMU console"); + + // ==== Normal Speed Mode ==== + // Profile code: a single NOP instruction + // + // The clock units are "1 nop in [CGB] doublespeed mode". + // So when *not* running in CGB doublespeed mode you + // have to divide by 2 to get the correct cycle count. + // + // You should see the message "NOP TIME: 2". + // + // So in this case, divide the printed value by 2 = The NOP took "1" cycle + + __critical { // Temporarily turn off interrupts for more accurate measurements + EMU_PROFILE_BEGIN("Profile a single NOP instruction at Normal Speed"); + __asm__("nop"); + EMU_PROFILE_END("NOP TIME:"); + } + + + #ifdef NINTENDO + // ==== Color Game Boy in Double Speed Mode ==== + // Profile code: a single NOP instruction + // + // The EMU_PROFILE_BEGIN/END macros don't support the + // Color Game Boy (CGB) in double speed mode (cpu_fast()). + // The example below shows what to use instead (and how to + // check for a CGB and turn on Double Speed mode). + // + // Check and only run this test if on CGB hardware + if (DEVICE_SUPPORTS_COLOR) { + + // Set CGB into double speed mode + // (Requires passing -Wm-yc or -Wm-yC with Lcc during build time) + cpu_fast(); + // Set some default DMG styled colors in the CGB Palette + set_default_palette(); + + // In CGB Double Speed mode, you don't have to + // divide by 2 to get the cycle count. + // + // You should see the message "NOP TIME: 1". + + __critical { // Temporarily turn off interrupts for more accurate measurements + EMU_PROFILE_BEGIN("Profile a single NOP instruction at CGB Double Speed"); + __asm__("nop"); + // The "-4+" subtracts 4 clocks to compensate for the ones + // used by the debug message itself (Normal speed uses -8) + EMU_MESSAGE("NOP TIME:%-4+LASTCLKS%"); + } + + // Return the CGB to normal speed + cpu_slow(); + } + + __critical { // Temporarily turn off interrupts for more accurate measurements + + int c; + + // Profile code in a loop + EMU_PROFILE_BEGIN("Profile code in a loop"); + for(c=0; c<5; c++) { + // Do something + printf("%d\n", c); + } + // Elapsed cycle count output is in hex. + // Remember to divide by 2 for the result (Normal Speed) + EMU_PROFILE_END("LOOP TIME:"); + } + #endif // NINTENDO + + // ==== Some other things you can print ==== + + // - For Game Boy TOTALCLKS shows the clocks counter ("internal divider") + // - For SMS/GG TOTALCLKS is relative to CLKS2VBLANK (so at most it can be the max clocks to vblank) + EMU_MESSAGE("Total Clocks: %TOTALCLKS%"); + + // CLKS2VBLANK + EMU_MESSAGE("Clocks until VBLANK: %CLKS2VBLANK%"); + + // Which Banks are currently active (for MBC based cartridges) + EMU_MESSAGE("Current ROM bank: %ROMBANK%"); + EMU_MESSAGE("Current SRAM bank: %SRAMBANK%"); + // These are not banked on DMG/MGB Game Boys + EMU_MESSAGE("Current VRAM bank: %VRAMBANK%"); + EMU_MESSAGE("Current WRAM bank: %WRAMBANK%"); + + // Registers (All in this case, or individual ones) + EMU_MESSAGE("All Registers: %ALLREGS%"); + + // Simple addition with a register + EMU_MESSAGE("Register A + 1: %(A+1)%"); + + // Note: %SCANLINE% is available in Emulicious (for SMS/GG/GB/GBC) but not BGB + EMU_MESSAGE("Current Scanline: %SCANLINE%"); + + #if defined(NINTENDO) + // Read the LY Register a couple times + // (Current Y coordinate being rendered to the LCD) + EMU_MESSAGE("LY Register (0xFF44): %($ff44)%"); + EMU_MESSAGE("LY Register (0xFF44): %($ff44)%"); + // Now print a conditional debug message using it + EMU_MESSAGE("Is LY Register > Line 67: %($ff44)>67%Yes;No;"); + #endif + + + #if defined(NINTENDO) + // Print some profile info using a built-in function. + EMU_MESSAGE("The following lines contain: PROFILE,(SP+$0),(SP+$1),A,TOTALCLKS,ROMBANK,WRAMBANK"); + + EMU_profiler_message(); + + // It's equivalent to: + EMU_MESSAGE("PROFILE,%(SP+$0)%,%(SP+$1)%,%A%,%TOTALCLKS%,%ROMBANK%,%WRAMBANK%"); + + #elif defined(SEGA) + EMU_MESSAGE("PROFILE,%(SP+$0)%,%(SP+$1)%,%A%,%ROMBANK%,%WRAMBANK%"); + #endif + + uint8_t var0 = 16; + int16_t var1 = -10; + EMU_printf("var0: %hd; var1: %d; var0*var1=%d", (uint8_t)var0, var1, var0 * var1); + + // The EMU_TEXT() macro will accept a non-quoted string + EMU_TEXT("The End"); + + return 0; +} diff --git a/gbdk-lib/examples/gb/emu_debug/Makefile b/gbdk-lib/examples/gb/emu_debug/Makefile @@ -1,17 +0,0 @@ -CC = ../../../bin/lcc -Wl-m -Wl-j -Wm-yS -Wm-yc - -BINS = emu_debug.gb - -all: $(BINS) - -compile.bat: Makefile - @echo "REM Automatically generated from Makefile" > compile.bat - @make -sn | sed y/\\//\\\\/ | grep -v make >> compile.bat - -# Compile and link single file in one pass -%.gb: %.c - $(CC) -o $@ $< - -clean: - rm -f *.o *.lst *.map *.gb *~ *.rel *.cdb *.ihx *.lnk *.sym *.asm *.noi - diff --git a/gbdk-lib/examples/gb/emu_debug/emu_debug.c b/gbdk-lib/examples/gb/emu_debug/emu_debug.c @@ -1,147 +0,0 @@ -#include <gb/gb.h> -#include <stdint.h> -#include <stdio.h> // Just for printf() -#include <gb/cgb.h> // Just for the cpu_fast()/slow() calls in CGB 2x example - -#include <gb/emu_debug.h> // Use this include to add the Emu debug functions - - -// This example shows how to use support for profiling -// and logging to the debug window in the emulator (BGB or Emulicious). -// -// 1. Build this ROM (emu_debug.gb) then load it in the emulator (BGB or Emulicious) -// 2. Open the internal debugger by pressing the "ESC" or "F1" key -// 3. From the debugger menu choose "debug messages" to open the debug messages window -// 4. Reset the gameboy (you may need to press F9 in the debugger to resume running) -// 5. The debug window will show the debug messages -// -// See the BGB Manual for more information -// ("expressions, breakpoint conditions, and debug messages") -// https://bgb.bircd.org/manual.html#expressions - -int main(void) -{ - int c; - - SHOW_BKG; - DISPLAY_ON; - enable_interrupts(); - - // Display a message on the GameBoy's screen - printf("Message to the \nGameBoy screen\n"); - - // Log a message to the Emulator debug message window - EMU_MESSAGE(""); // new line - EMU_MESSAGE("Message to the EMU console"); - - // ==== Normal Speed Mode ==== - // Profile code: a single NOP instruction - // - // The clock units are "1 nop in [CGB] doublespeed mode". - // So when *not* running in CGB doublespeed mode you - // have to divide by 2 to get the correct cycle count. - // - // You should see the message "NOP TIME: 2". - // - // So in this case, divide the printed value by 2 = The NOP took "1" cycle - - __critical { // Temporarily turn off interrupts for more accurate measurements - EMU_PROFILE_BEGIN("Profile a single NOP instruction at Normal Speed"); - __asm__("nop"); - EMU_PROFILE_END("NOP TIME:"); - } - - - // ==== Color Game Boy in Double Speed Mode ==== - // Profile code: a single NOP instruction - // - // The EMU_PROFILE_BEGIN/END macros don't support the - // Color Game Boy (CGB) in double speed mode (cpu_fast()). - // The example below shows what to use instead (and how to - // check for a CGB and turn on Double Speed mode). - // - // Check and only run this test if on CGB hardware - if (DEVICE_SUPPORTS_COLOR) { - - // Set CGB into double speed mode - // (Requires passing -Wm-yc or -Wm-yC with Lcc during build time) - cpu_fast(); - // Set some default DMG styled colors in the CGB Palette - set_default_palette(); - - // In CGB Double Speed mode, you don't have to - // divide by 2 to get the cycle count. - // - // You should see the message "NOP TIME: 1". - - __critical { // Temporarily turn off interrupts for more accurate measurements - EMU_PROFILE_BEGIN("Profile a single NOP instruction at CGB Double Speed"); - __asm__("nop"); - // The "-4+" subtracts 4 clocks to compensate for the ones - // used by the debug message itself (Normal speed uses -8) - EMU_MESSAGE("NOP TIME:%-4+LASTCLKS%"); - } - - // Return the CGB to normal speed - cpu_slow(); - } - - - __critical { // Temporarily turn off interrupts for more accurate measurements - - // Profile code in a loop - EMU_PROFILE_BEGIN("Profile code in a loop"); - for(c=0; c<5; c++) { - // Do something - printf("%d\n", c); - } - // Elapsed cycle count output is in hex. - // Remember to divide by 2 for the result (Normal Speed) - EMU_PROFILE_END("LOOP TIME:"); - } - - - // ==== Some other things you can print ==== - - // TOTALCLKS shows the clocks counter ("internal divider") in the BGB IO map - EMU_MESSAGE("Total Clocks: %TOTALCLKS%"); - - // CLKS2VBLANK - EMU_MESSAGE("Clocks until VBLANK: %CLKS2VBLANK%"); - - // Which Banks are currently active (for MBC based cartridges) - EMU_MESSAGE("Current ROM bank: %ROMBANK%"); - EMU_MESSAGE("Current SRAM bank: %SRAMBANK%"); - // These are only banked in the CGB - EMU_MESSAGE("Current VRAM bank: %VRAMBANK%"); - EMU_MESSAGE("Current WRAM bank: %WRAMBANK%"); - - // Registers (All in this case, or individual ones) - EMU_MESSAGE("All Registers: %ALLREGS%"); - - // Simple addition with a register - EMU_MESSAGE("Register A + 1: %(A+1)%"); - - // Read the LY Register a couple times - // (Current Y coordinate being rendered to the LCD) - EMU_MESSAGE("LY Register (0xFF44): %($ff44)%"); - EMU_MESSAGE("LY Register (0xFF44): %($ff44)%"); - // Now print a conditional debug message using it - EMU_MESSAGE("Is LY Register > Line 67: %($ff44)>67%Yes;No;"); - - // Print some profile info using a built-in function. - EMU_MESSAGE("The following lines contain: PROFILE,(SP+$0),(SP+$1),A,TOTALCLKS,ROMBANK,WRAMBANK"); - EMU_profiler_message(); - // It's equivalent to: - EMU_MESSAGE("PROFILE,%(SP+$0)%,%(SP+$1)%,%A%,%TOTALCLKS%,%ROMBANK%,%WRAMBANK%"); - - uint8_t var0 = 16; - int16_t var1 = -10; - // - EMU_printf("var0: %hd; var1: %d; var0*var1=%d", (uint8_t)var0, var1, var0 * var1); - - // The EMU_TEXT() macro will accept a non-quoted string - EMU_TEXT("The End"); - - return 0; -} diff --git a/gbdk-lib/include/gb/emu_debug.h b/gbdk-lib/include/gb/emu_debug.h @@ -110,8 +110,13 @@ __endasm @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) @@ -124,15 +129,17 @@ __endasm \endcode */ +#if defined(NINTENDO) void EMU_profiler_message(); #define BGB_profiler_message() EMU_profiler_message() +#endif // NINTENDO /** 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. - Result string MUST BE LESS OR EQUAL THAN 128 BYTES LONG, INCLUDING THE TRAILIG ZERO BYTE! + Result string MUST BE LESS OR EQUAL THAN 128 BYTES LONG, INCLUDING THE TRAILIG ZERO BYTE! Currently supported: \li \%hx (char as hex) @@ -151,7 +158,9 @@ void EMU_profiler_message(); void EMU_printf(const char *format, ...) OLDCALL; #define BGB_printf(...) EMU_printf(__VA_ARGS__) +#ifdef NINTENDO static void * __EMU_PROFILER_INIT = &EMU_profiler_message; +#endif // NINTENDO /** The Emulator will break into debugger when encounters this line */ diff --git a/gbdk-lib/include/gbdk/emu_debug.h b/gbdk-lib/include/gbdk/emu_debug.h @@ -0,0 +1,12 @@ +#ifndef __GBDK_EMU_DEBUG_H_INCLUDE +#define __GBDK_EMU_DEBUG_H_INCLUDE + +#if defined(__TARGET_gb) || defined(__TARGET_ap) || defined(__TARGET_sms) || defined(__TARGET_gg) + #include <gb/emu_debug.h> +#elif defined(__TARGET_duck) + #error Not implemented yet +#else + #error Unrecognized port +#endif + +#endif + diff --git a/gbdk-lib/libc/targets/z80/emu_debug_printf.s b/gbdk-lib/libc/targets/z80/emu_debug_printf.s @@ -0,0 +1,44 @@ + .include "global.s" + + .title "EMU_debug" + .module EMU_debug + + .globl _sprintf + + .area _DATA + +ret_save: + .ds 0x02 +printf_buffer: + .ds 0x80 + + .area _HOME + + ;; EMU_printf(fmt, ...) +_EMU_printf:: + di + pop de + ld hl, #ret_save + ld (hl), e + inc hl + ld (hl), d + + ld de, #printf_buffer + push de + call _sprintf + pop hl + + ld d,d + jr 1$ + .dw 0x6464 + .dw 0x0001 + .dw #printf_buffer + .dw 0 +1$: + ld hl, #ret_save + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + ei + jp (hl) diff --git a/gbdk-lib/libc/targets/z80/gg/Makefile b/gbdk-lib/libc/targets/z80/gg/Makefile @@ -26,6 +26,7 @@ ASSRC = set_interrupts.s \ int.s nmi.s \ mode.s clock.s \ delay.s \ + emu_debug_printf.s \ memset_small.s \ far_ptr.s \ gb_decompress.s \ diff --git a/gbdk-lib/libc/targets/z80/sms/Makefile b/gbdk-lib/libc/targets/z80/sms/Makefile @@ -26,6 +26,7 @@ ASSRC = set_interrupts.s \ int.s nmi.s \ mode.s clock.s \ delay.s \ + emu_debug_printf.s \ memset_small.s \ far_ptr.s \ gb_decompress.s \

This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.