gbdk-2020 | GameBoy Development Kit |
| download: https://git.y1.nz/archives/gbdk.tar.gz | |
| README | Files | Log | Refs | LICENSE |
commit d2f10491ef6e3e9216f73300bfbb2d14cfe5e4bb parent 97868b0b5eea57b7cb6510a3798f620ac7d824ee Author: Toxa <56631470+untoxa@users.noreply.github.com> Date: Sat, 16 Oct 2021 00:18:45 +0300 Merge pull request #280 from gbdk-2020/feature/duck support for megaduck Diffstat:
53 files changed, 1842 insertions(+), 69 deletions(-)
diff --git a/Makefile b/Makefile @@ -11,7 +11,7 @@ PKG = gbdk VER = 3.00 PORTS=gbz80 z80 -PLATFORMS=gb ap gg sms +PLATFORMS=gb ap duck gg sms # Prefix to add to the standard tools. Usefull for a standard gcc # cross-compile. diff --git a/gbdk-lib/Makefile.common b/gbdk-lib/Makefile.common @@ -11,7 +11,7 @@ ifndef PORTS PORTS = gbz80 z80 endif ifndef PLATFORMS -PLATFORMS = gb ap gg sms +PLATFORMS = gb ap duck gg sms endif ifndef SDCCLIB diff --git a/gbdk-lib/examples/cross-platform/banks/Makefile b/gbdk-lib/examples/cross-platform/banks/Makefile @@ -7,12 +7,13 @@ 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 sms gg -TARGETS=gb pocket sms gg +# Possible are: gb gbc pocket megaduck sms gg +TARGETS=gb pocket megaduck sms gg # 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 = diff --git a/gbdk-lib/examples/cross-platform/banks/Makefile.targets b/gbdk-lib/examples/cross-platform/banks/Makefile.targets @@ -31,6 +31,12 @@ 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: diff --git a/gbdk-lib/examples/cross-platform/banks_autobank/Makefile b/gbdk-lib/examples/cross-platform/banks_autobank/Makefile @@ -5,12 +5,13 @@ 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 sms gg -TARGETS=gb pocket sms gg +# Possible are: gb gbc pocket megaduck sms gg +TARGETS=gb pocket megaduck sms gg # 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 = diff --git a/gbdk-lib/examples/cross-platform/banks_autobank/Makefile.targets b/gbdk-lib/examples/cross-platform/banks_autobank/Makefile.targets @@ -31,6 +31,12 @@ 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: diff --git a/gbdk-lib/examples/cross-platform/banks_farptr/Makefile b/gbdk-lib/examples/cross-platform/banks_farptr/Makefile @@ -5,12 +5,13 @@ 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 sms gg -TARGETS=gb pocket sms gg +# Possible are: gb gbc pocket megaduck sms gg +TARGETS=gb pocket megaduck sms gg # 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 = diff --git a/gbdk-lib/examples/cross-platform/banks_farptr/Makefile.targets b/gbdk-lib/examples/cross-platform/banks_farptr/Makefile.targets @@ -31,6 +31,12 @@ 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: diff --git a/gbdk-lib/examples/cross-platform/banks_nonintrinsic/Makefile b/gbdk-lib/examples/cross-platform/banks_nonintrinsic/Makefile @@ -5,12 +5,13 @@ 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 sms gg -TARGETS=gb pocket sms gg +# Possible are: gb gbc pocket megaduck sms gg +TARGETS=gb pocket megaduck sms gg # 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 = diff --git a/gbdk-lib/examples/cross-platform/banks_nonintrinsic/Makefile.targets b/gbdk-lib/examples/cross-platform/banks_nonintrinsic/Makefile.targets @@ -31,6 +31,12 @@ 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: diff --git a/gbdk-lib/examples/cross-platform/fonts/Makefile b/gbdk-lib/examples/cross-platform/fonts/Makefile @@ -5,12 +5,13 @@ 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 sms gg -TARGETS=gb pocket sms gg +# Possible are: gb gbc pocket megaduck sms gg +TARGETS=gb pocket megaduck sms gg # 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 = diff --git a/gbdk-lib/examples/cross-platform/fonts/Makefile.targets b/gbdk-lib/examples/cross-platform/fonts/Makefile.targets @@ -31,6 +31,12 @@ 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: diff --git a/gbdk-lib/examples/cross-platform/gbdecompress/Makefile b/gbdk-lib/examples/cross-platform/gbdecompress/Makefile @@ -6,12 +6,13 @@ PNG2ASSET = $(GBDK_HOME)/bin/png2asset # 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 sms gg -TARGETS=gb pocket sms gg +# Possible are: gb gbc pocket megaduck sms gg +TARGETS=gb pocket megaduck sms gg # 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 = diff --git a/gbdk-lib/examples/cross-platform/gbdecompress/Makefile.targets b/gbdk-lib/examples/cross-platform/gbdecompress/Makefile.targets @@ -31,6 +31,12 @@ 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: diff --git a/gbdk-lib/examples/cross-platform/incbin/Makefile b/gbdk-lib/examples/cross-platform/incbin/Makefile @@ -5,12 +5,13 @@ 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 sms gg -TARGETS=gb pocket sms gg +# Possible are: gb gbc pocket megaduck sms gg +TARGETS=gb pocket megaduck sms gg # 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 = diff --git a/gbdk-lib/examples/cross-platform/incbin/Makefile.targets b/gbdk-lib/examples/cross-platform/incbin/Makefile.targets @@ -31,6 +31,12 @@ 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: diff --git a/gbdk-lib/examples/cross-platform/large_map/Makefile b/gbdk-lib/examples/cross-platform/large_map/Makefile @@ -5,12 +5,13 @@ 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 sms gg +# Possible are: gb gbc pocket megaduck sms gg TARGETS=gb gg # 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 = diff --git a/gbdk-lib/examples/cross-platform/large_map/Makefile.targets b/gbdk-lib/examples/cross-platform/large_map/Makefile.targets @@ -31,6 +31,12 @@ 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: diff --git a/gbdk-lib/examples/cross-platform/metasprites/Makefile b/gbdk-lib/examples/cross-platform/metasprites/Makefile @@ -6,12 +6,13 @@ PNG2ASSET = $(GBDK_HOME)/bin/png2asset # 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 sms gg -TARGETS=gb pocket sms gg +# Possible are: gb gbc pocket megaduck sms gg +TARGETS=gb pocket megaduck sms gg # 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 = diff --git a/gbdk-lib/examples/cross-platform/metasprites/Makefile.targets b/gbdk-lib/examples/cross-platform/metasprites/Makefile.targets @@ -31,6 +31,12 @@ 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: diff --git a/gbdk-lib/examples/cross-platform/pong/Makefile b/gbdk-lib/examples/cross-platform/pong/Makefile @@ -5,12 +5,13 @@ 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 sms gg -TARGETS=gb pocket sms gg +# Possible are: gb gbc pocket megaduck sms gg +TARGETS=gb pocket megaduck sms gg # Configure platform specific LCC flags here: LCCFLAGS_gb = -Wm-ys -Wl-yt0x1B # Set an MBC for banking (1B-ROM+MBC5+RAM+BATT) LCCFLAGS_pocket = -Wm-ys -Wl-yt0x1B # Usually the same as required for .gb +LCCFLAGS_duck = -Wm-ys -Wl-yt0x1B # Usually the same as required for .gb LCCFLAGS_gbc = -Wm-ys -Wl-yt0x1B -Wm-yc # Same as .gb with: -Wm-yc (gb & gbc) or Wm-yC (gbc exclusive) LCCFLAGS_sms = LCCFLAGS_gg = diff --git a/gbdk-lib/examples/cross-platform/pong/Makefile.targets b/gbdk-lib/examples/cross-platform/pong/Makefile.targets @@ -31,6 +31,12 @@ 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: diff --git a/gbdk-lib/examples/cross-platform/randtest/Makefile b/gbdk-lib/examples/cross-platform/randtest/Makefile @@ -5,12 +5,13 @@ 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 sms gg -TARGETS=gb pocket sms gg +# Possible are: gb gbc pocket megaduck sms gg +TARGETS=gb pocket megaduck sms gg # 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 = diff --git a/gbdk-lib/examples/cross-platform/randtest/Makefile.targets b/gbdk-lib/examples/cross-platform/randtest/Makefile.targets @@ -31,6 +31,12 @@ 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: diff --git a/gbdk-lib/examples/cross-platform/rle_map/Makefile b/gbdk-lib/examples/cross-platform/rle_map/Makefile @@ -7,13 +7,14 @@ 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 sms gg +# Possible are: gb gbc pocket megaduck sms gg #TARGETS=gb pocket sms gg TARGETS=gb gg # Configure platform specific LCC flags here: LCCFLAGS_gb = -Wl-yt0x19 -Wl-yo4 -Wm-yS -Wm-yn"$(PROJECTNAME)" LCCFLAGS_pocket = -Wl-yt0x19 -Wl-yo4 -Wm-yS -Wm-yn"$(PROJECTNAME)" +LCCFLAGS_duck = -Wl-yt0x19 -Wl-yo4 -Wm-yS -Wm-yn"$(PROJECTNAME)" LCCFLAGS_sms = -Wl-yo4 -Wm-yS LCCFLAGS_gg = -Wl-yo4 -Wm-yS diff --git a/gbdk-lib/examples/cross-platform/rle_map/Makefile.targets b/gbdk-lib/examples/cross-platform/rle_map/Makefile.targets @@ -19,12 +19,24 @@ 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: diff --git a/gbdk-lib/examples/cross-platform/scroller/Makefile b/gbdk-lib/examples/cross-platform/scroller/Makefile @@ -5,12 +5,13 @@ 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 sms gg -TARGETS=gb pocket sms gg +# Possible are: gb gbc pocket megaduck sms gg +TARGETS=gb pocket megaduck sms gg # 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 = diff --git a/gbdk-lib/examples/cross-platform/scroller/Makefile.targets b/gbdk-lib/examples/cross-platform/scroller/Makefile.targets @@ -31,6 +31,12 @@ 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: diff --git a/gbdk-lib/include/gb/gb.h b/gbdk-lib/include/gb/gb.h @@ -17,6 +17,8 @@ #define ANALOGUEPOCKET #elif defined(__TARGET_gb) #define GAMEBOY +#elif defined(__TARGET_duck) +#define MEGADUCK #endif @@ -458,6 +460,12 @@ __endasm; \ */ #define BANKREF_EXTERN(VARNAME) extern const void __bank_ ## VARNAME; +/** Makes MEGADUCK MBC switch the active ROM bank + @param b ROM bank to switch to +*/ +#define SWITCH_ROM_MEGADUCK(b) \ + _current_bank = (b), *(uint8_t *)0x0001 = (b) + /** Makes MBC1 and other compatible MBCs switch the active ROM bank @param b ROM bank to switch to @@ -465,12 +473,16 @@ __endasm; \ #define SWITCH_ROM_MBC1(b) \ _current_bank = (b), *(uint8_t *)0x2000 = (b) -/** Makes MBC1, MBC5 (4M ROMs) and other compatible MBCs switch the active ROM bank +/** Makes default platform MBC switch the active ROM bank @param b ROM bank to switch to (max 255) - @see SWITCH_ROM_MBC1, SWITCH_ROM_MBC5 + @see SWITCH_ROM_MBC1, SWITCH_ROM_MBC5, SWITCH_ROM_MEGADUCK */ +#if defined(__TARGET_duck) +#define SWITCH_ROM SWITCH_ROM_MEGADUCK +#else #define SWITCH_ROM SWITCH_ROM_MBC1 +#endif /** Switches SRAM bank on MBC1 and other compaticle MBCs @param b SRAM bank to switch to diff --git a/gbdk-lib/include/gb/hardware.h b/gbdk-lib/include/gb/hardware.h @@ -161,7 +161,7 @@ __BYTE_REG AUD3WAVE[16]; __REG LCDC_REG; /**< LCD control */ #define rLCDC LCDC_REG -#ifdef __TARGET_ap +#if defined(__TARGET_ap) #define LCDCF_OFF 0b00000000 #define LCDCF_ON 0b00000001 #define LCDCF_WIN9800 0b00000000 @@ -186,37 +186,62 @@ __REG LCDC_REG; /**< LCD control */ #define LCDCF_B_OBJ16 5 #define LCDCF_B_OBJON 6 #define LCDCF_B_BGON 7 +#elif defined(__TARGET_duck) +#define LCDCF_OFF 0b00000000 +#define LCDCF_ON 0b10000000 +#define LCDCF_WIN9800 0b00000000 +#define LCDCF_WIN9C00 0b00001000 +#define LCDCF_WINOFF 0b00000000 +#define LCDCF_WINON 0b00100000 +#define LCDCF_BG8800 0b00000000 +#define LCDCF_BG8000 0b00010000 +#define LCDCF_BG9800 0b00000000 +#define LCDCF_BG9C00 0b00000100 +#define LCDCF_OBJ8 0b00000000 +#define LCDCF_OBJ16 0b00000010 +#define LCDCF_OBJOFF 0b00000000 +#define LCDCF_OBJON 0b00000001 +#define LCDCF_BGOFF 0b00000000 +#define LCDCF_BGON 0b01000000 +#define LCDCF_B_ON 7 +#define LCDCF_B_WIN9C00 3 +#define LCDCF_B_WINON 5 +#define LCDCF_B_BG8000 4 +#define LCDCF_B_BG9C00 2 +#define LCDCF_B_OBJ16 1 +#define LCDCF_B_OBJON 0 +#define LCDCF_B_BGON 6 #else -#define LCDCF_OFF 0b00000000 /**< LCD Control: Off */ -#define LCDCF_ON 0b10000000 /**< LCD Control: On */ -#define LCDCF_WIN9800 0b00000000 /**< Window Tile Map: Use 9800 Region */ -#define LCDCF_WIN9C00 0b01000000 /**< Window Tile Map: Use 9C00 Region */ -#define LCDCF_WINOFF 0b00000000 /**< Window Display: Hidden */ -#define LCDCF_WINON 0b00100000 /**< Window Display: Visible */ -#define LCDCF_BG8800 0b00000000 /**< BG & Window Tile Data: Use 8800 Region */ -#define LCDCF_BG8000 0b00010000 /**< BG & Window Tile Data: Use 8000 Region */ -#define LCDCF_BG9800 0b00000000 /**< BG Tile Map: use 9800 Region */ -#define LCDCF_BG9C00 0b00001000 /**< BG Tile Map: use 9C00 Region */ -#define LCDCF_OBJ8 0b00000000 /**< Sprites Size: 8x8 pixels */ -#define LCDCF_OBJ16 0b00000100 /**< Sprites Size: 8x16 pixels */ -#define LCDCF_OBJOFF 0b00000000 /**< Sprites Display: Hidden */ -#define LCDCF_OBJON 0b00000010 /**< Sprites Display: Visible */ -#define LCDCF_BGOFF 0b00000000 /**< Background Display: Hidden */ -#define LCDCF_BGON 0b00000001 /**< Background Display: Visible */ -#define LCDCF_B_ON 7 /**< Bit for LCD On/Off Select */ -#define LCDCF_B_WIN9C00 6 /**< Bit for Window Tile Map Region Select */ -#define LCDCF_B_WINON 5 /**< Bit for Window Display On/Off Control */ -#define LCDCF_B_BG8000 4 /**< Bit for BG & Window Tile Data Region Select */ -#define LCDCF_B_BG9C00 3 /**< Bit for BG Tile Map Region Select */ -#define LCDCF_B_OBJ16 2 /**< Bit for Sprites Size Select */ -#define LCDCF_B_OBJON 1 /**< Bit for Sprites Display Visible/Hidden Select */ -#define LCDCF_B_BGON 0 /**< Bit for Background Display Visible/Hidden Select */ +#define LCDCF_OFF 0b00000000 /**< LCD Control: Off */ +#define LCDCF_ON 0b10000000 /**< LCD Control: On */ +#define LCDCF_WIN9800 0b00000000 /**< Window Tile Map: Use 9800 Region */ +#define LCDCF_WIN9C00 0b01000000 /**< Window Tile Map: Use 9C00 Region */ +#define LCDCF_WINOFF 0b00000000 /**< Window Display: Hidden */ +#define LCDCF_WINON 0b00100000 /**< Window Display: Visible */ +#define LCDCF_BG8800 0b00000000 /**< BG & Window Tile Data: Use 8800 Region */ +#define LCDCF_BG8000 0b00010000 /**< BG & Window Tile Data: Use 8000 Region */ +#define LCDCF_BG9800 0b00000000 /**< BG Tile Map: use 9800 Region */ +#define LCDCF_BG9C00 0b00001000 /**< BG Tile Map: use 9C00 Region */ +#define LCDCF_OBJ8 0b00000000 /**< Sprites Size: 8x8 pixels */ +#define LCDCF_OBJ16 0b00000100 /**< Sprites Size: 8x16 pixels */ +#define LCDCF_OBJOFF 0b00000000 /**< Sprites Display: Hidden */ +#define LCDCF_OBJON 0b00000010 /**< Sprites Display: Visible */ +#define LCDCF_BGOFF 0b00000000 /**< Background Display: Hidden */ +#define LCDCF_BGON 0b00000001 /**< Background Display: Visible */ +#define LCDCF_B_ON 7 /**< Bit for LCD On/Off Select */ +#define LCDCF_B_WIN9C00 6 /**< Bit for Window Tile Map Region Select */ +#define LCDCF_B_WINON 5 /**< Bit for Window Display On/Off Control */ +#define LCDCF_B_BG8000 4 /**< Bit for BG & Window Tile Data Region Select */ +#define LCDCF_B_BG9C00 3 /**< Bit for BG Tile Map Region Select */ +#define LCDCF_B_OBJ16 2 /**< Bit for Sprites Size Select */ +#define LCDCF_B_OBJON 1 /**< Bit for Sprites Display Visible/Hidden Select */ +#define LCDCF_B_BGON 0 /**< Bit for Background Display Visible/Hidden Select */ #endif __REG STAT_REG; /**< LCD status */ #define rSTAT STAT_REG -#ifdef __TARGET_ap +#if defined(__TARGET_ap) #define STATF_LYC 0b00000010 #define STATF_MODE10 0b00000100 #define STATF_MODE01 0b00001000 diff --git a/gbdk-lib/include/gbdk/bcd.h b/gbdk-lib/include/gbdk/bcd.h @@ -1,7 +1,7 @@ #ifndef __GBDK_BCD_H_INCLUDE #define __GBDK_BCD_H_INCLUDE -#if defined(__TARGET_gb) || defined(__TARGET_ap) +#if defined(__TARGET_gb) || defined(__TARGET_ap) || defined(__TARGET_duck) #include <gb/bcd.h> #elif defined(__TARGET_sms) || defined(__TARGET_gg) #error Not implemented yet diff --git a/gbdk-lib/include/gbdk/gbdecompress.h b/gbdk-lib/include/gbdk/gbdecompress.h @@ -1,7 +1,7 @@ #ifndef __GB_DECOMPRESS_H_INCLUDE #define __GB_DECOMPRESS_H_INCLUDE -#if defined(__TARGET_gb) || defined(__TARGET_ap) +#if defined(__TARGET_gb) || defined(__TARGET_ap) || defined(__TARGET_duck) #include <gb/gbdecompress.h> #elif defined(__TARGET_sms) || defined(__TARGET_gg) #include <sms/gbdecompress.h> diff --git a/gbdk-lib/include/gbdk/metasprites.h b/gbdk-lib/include/gbdk/metasprites.h @@ -1,7 +1,7 @@ #ifndef __PLAT_METASPRITES_H_INVCLUDE #define __PLAT_METASPRITES_H_INVCLUDE -#if defined(__TARGET_gb) || defined(__TARGET_ap) +#if defined(__TARGET_gb) || defined(__TARGET_ap) || defined(__TARGET_duck) #include <gb/metasprites.h> #elif defined(__TARGET_sms) || defined(__TARGET_gg) #include <sms/metasprites.h> diff --git a/gbdk-lib/include/gbdk/platform.h b/gbdk-lib/include/gbdk/platform.h @@ -1,7 +1,7 @@ #ifndef __PLATFORM_H_INCLUDE #define __PLATFORM_H_INCLUDE -#if defined(__TARGET_gb) || defined(__TARGET_ap) +#if defined(__TARGET_gb) || defined(__TARGET_ap) || defined(__TARGET_duck) #include <gb/gb.h> #include <gb/cgb.h> #include <gb/sgb.h> diff --git a/gbdk-lib/include/gbdk/rledecompress.h b/gbdk-lib/include/gbdk/rledecompress.h @@ -14,7 +14,7 @@ #define RLE_STOP 0 -#if defined(__TARGET_gb) || defined(__TARGET_ap) +#if defined(__TARGET_gb) || defined(__TARGET_ap) || defined(__TARGET_duck) /** Initialize the RLE decompressor with RLE data at address __data__ @param data Pointer to start of RLE compressed data diff --git a/gbdk-lib/libc/Makefile b/gbdk-lib/libc/Makefile @@ -7,7 +7,7 @@ ifeq ($(PORTS),) endif ifeq ($(PLATFORMS),) - PLATFORMS = gb ap gg sms + PLATFORMS = gb ap duck gg sms endif TOPDIR = .. diff --git a/gbdk-lib/libc/targets/gbz80/___sdcc_bcall.s b/gbdk-lib/libc/targets/gbz80/___sdcc_bcall.s @@ -15,7 +15,7 @@ banked_call:: ; Performs a long call. inc hl ; Yes this should be here push hl ; Push the real return address ldh (__current_bank),a - ld (.MBC1_ROM_PAGE),a ; Perform the switch + ld (.MBC_ROM_PAGE),a ; Perform the switch ld l,e ld h,d rst 0x20 @@ -23,5 +23,5 @@ banked_ret:: pop hl ; Get the return address pop af ; Pop the old bank ldh (__current_bank),a - ld (.MBC1_ROM_PAGE),a + ld (.MBC_ROM_PAGE),a jp (hl) diff --git a/gbdk-lib/libc/targets/gbz80/___sdcc_bcall_ehl.s b/gbdk-lib/libc/targets/gbz80/___sdcc_bcall_ehl.s @@ -7,9 +7,9 @@ ldh a,(__current_bank) push af ; Push the current bank onto the stack ld a, e ldh (__current_bank),a - ld (.MBC1_ROM_PAGE),a ; Perform the switch + ld (.MBC_ROM_PAGE),a ; Perform the switch rst 0x20 pop af ; Pop the old bank ldh (__current_bank),a - ld (.MBC1_ROM_PAGE),a + ld (.MBC_ROM_PAGE),a ret diff --git a/gbdk-lib/libc/targets/gbz80/crash_handler.s b/gbdk-lib/libc/targets/gbz80/ap/crash_handler.s diff --git a/gbdk-lib/libc/targets/gbz80/ap/global.s b/gbdk-lib/libc/targets/gbz80/ap/global.s @@ -20,6 +20,7 @@ ;; MBC Equates .MBC1_ROM_PAGE = 0x2000 ; Address to write to for MBC1 switching + .MBC_ROM_PAGE = 0x2000 ; Default platform MBC rom switching address rRAMG = 0x0000 ; $0000->$1fff rROMB0 = 0x2000 ; $2000->$2fff diff --git a/gbdk-lib/libc/targets/gbz80/duck/Makefile b/gbdk-lib/libc/targets/gbz80/duck/Makefile @@ -0,0 +1,53 @@ +# GB specific Makefile + +TOPDIR = ../../../.. + +THIS = duck +PORT = gbz80 + +CSRC = digits.c gprint.c gprintf.c gprintln.c gprintn.c + +ASSRC = cgb.s cgb_palettes.s cgb_compat.s \ + cpy_data.s \ + drawing.s drawing_isr.s color.s \ + f_ibm_full.s f_ibm_sh.s f_italic.s f_min.s f_spect.s \ + get_bk_t.s get_data.s get_tile.s \ + get_wi_t.s get_xy_t.s \ + get_addr.s \ + hiramcpy.s init_tt.s input.s \ + pad.s \ + serial.s set_bk_t.s set_tile.s \ + set_data.s set_prop.s set_spr.s set_wi_t.s set_xy_t.s \ + set_1bit_data.s \ + sgb.s font.s font_color.s delay.s \ + bgb_emu.s bgb_emu_printf.s \ + nowait.s far_ptr.s \ + lcd.s joy.s tim.s \ + crash_handler.s \ + ___sdcc_bcall_ehl.s ___sdcc_bcall.s \ + mv_spr.s \ + pad_ex.s \ + mode.s clock.s \ + get_t.s set_t.s init_vram.s \ + fill_rect.s fill_rect_bk.s fill_rect_wi.s \ + metasprites.s metasprites_flip.s metasprites_hide.s metasprites_hide_spr.s \ + set_tile_submap.s set_win_tile_submap.s \ + gb_decompress.s gb_decompress_tiles.s \ + rle_decompress.s \ + heap.s \ + crt0.s + +ifeq ($(ASM),asxxxx) +ASSRC += sfr.s +endif +ifeq ($(ASM),rgbds) +ASSRC += stubs.s +endif + +CRT0 = crt0.s + +include $(TOPDIR)/Makefile.common + +AS = $(AS_GBZ80) + +include ../../../Makefile.platform diff --git a/gbdk-lib/libc/targets/gbz80/duck/crash_handler.s b/gbdk-lib/libc/targets/gbz80/duck/crash_handler.s @@ -0,0 +1,476 @@ +; Crash handler support +; Original code by ISSOtm +; Adapted by Toxa from gb-starter-kit: https://github.com/ISSOtm/gb-starter-kit + + .include "global.s" + + .globl _font_ibm + + SCRN_X = 160 ; Width of screen in pixels + SCRN_Y = 144 ; Height of screen in pixels + SCRN_X_B = 20 ; Width of screen in bytes + SCRN_Y_B = 18 ; Height of screen in bytes + + SCRN_VX = 256 ; Virtual width of screen in pixels + SCRN_VY = 256 ; Virtual height of screen in pixels + SCRN_VX_B = 32 ; Virtual width of screen in bytes + SCRN_VY_B = 32 ; Virtual height of screen in bytes + + + .area _CRASH_HEADER(ABS) + + .org 0x38 + di + jp ___HandleCrash + + + .area _HOME + +___HandleCrash:: + + ; We will use VRAM as scratch, since we are going to overwrite it for + ; screen output anyways. The thing is, we need to turn the LCD off + ; *without* affecting flags... fun task, eh? + + ; Note: it's assumed that this was jumped to with IME off. + ; Don't call this directly, use `rst Crash`. + + ld (wCrashA), a ; We need to have at least one working register, so... + ldh a, (.IE) ; We're also going to overwrite this + ld (wCrashIE), a + ldh a, (.LCDC) + ld (wCrashLCDC), a + ld a, #LCDCF_ON ; LCDCF_ON Make sure the LCD is turned on to avoid waiting infinitely + ldh (.LCDC), a + ld a, #IEF_VBLANK ; IEF_VBLANK + ld (.IE), a + ld a, #0 ; `xor a` would overwrite flags + ld (.IF), a ; No point in backing up that register, it's always changing + halt ; With interrupts disabled, this will exit when `IE & IF != 0` + nop ; Handle hardware bug if it becomes true *before* starting to execute the instruction (1-cycle window) + + ; We're now in VBlank! So we can now use VRAM as scratch for some cycles + ld a, #0 + ldh (.LCDC), a ; Turn off LCD so VRAM can always be safely accessed + ; Save regs + ld (vCrashSP), sp + ld sp, #vCrashSP + push hl + push de + push bc + ld a, (wCrashA) + push af + + ; We need to have all the data in bank 0, but we can't guarantee we were there + ldh a, (.VBK) + ld e, a + bit #0, a + jr z, .bank0 + ; Oh noes. We need to copy the data across banks! + ld hl, #vCrashAF + ld c, #(5 * 2) +.copyAcross: + ld b, (hl) + xor a + ldh (.VBK), a + ld (hl), b + inc l ; inc hl + inc a ; ld a, 1 + ldh (.VBK), a + dec c + jr nz, .copyAcross +.bank0: + xor a + ldh (.NR52), a ; Kill sound for this screen + + ldh (.VBK), a + ld a, e + ld (vCrashVBK), a ; copy vCrashVBK across banks + + ld a, #1 + ldh (.VBK), a + ld hl, #vCrashDumpScreen + ld b, #SCRN_Y_B +.writeAttrRow: + xor a + ld c, #(SCRN_X_B + 1) + rst #0x28 ; .MemsetSmall + ld a, l + add a, #(SCRN_VX_B - SCRN_X_B - 1) + ld l, a + dec b + jr nz, .writeAttrRow + xor a + ldh (.VBK), a + + ; Load palettes + ld a, #0x03 + ldh (.BGP), a + ld a, #0x80 + ldh (.BCPS), a + xor a + ld c, #.BCPD + ldh (c), a + ldh (c), a + dec a ; ld a, $FF + ldh (c), a + ldh (c), a + ldh (c), a + ldh (c), a + ldh (c), a + ldh (c), a + + ld a, #(SCRN_VY - SCRN_Y) + ldh (.SCY), a + ld a, #(SCRN_VX - SCRN_X - 4) + ldh (.SCX), a + + call loadfont + + ; Copy the registers to the dump viewers + ld hl, #vDumpHL + ld de, #vCrashHL + ld c, #4 + rst #0x30 ; .MemcpySmall + + ; We're now going to draw the screen, top to bottom + ld hl, #vCrashDumpScreen + + ; First 3 lines of text + ld de, #.header + ld b, #3 +.writeHeaderLine: + ld a, #0x20 ; " " + ld (hl+), a + ld c, #19 + rst #0x30 ; .MemcpySmall + ld a, #0x20 ; " " + ld (hl+), a + ld a, l + add a, #(SCRN_VX_B - SCRN_X_B - 1) + ld l, a + dec b + jr nz, .writeHeaderLine + + ; Blank line + ld a, #0x20 ; " " + ld c, #(SCRN_X_B + 1) + rst #0x28 ; .MemsetSmall + + ; AF and console model + ld l, #<vCrashDumpScreenRow4 + ld c, #4 + rst #0x30 ; .MemcpySmall + pop bc + call .printHexBC + ld c, #8 + rst #0x30 ; .MemcpySmall + ld a, (__cpu) + call .printHexA + ld a, #0x20 ; " " + ld (hl+), a + ld (hl+), a + ld (hl+), a + + ; BC and DE + ld l, #<vCrashDumpScreenRow5 + ld c, #4 + rst #0x30 ; .MemcpySmall + pop bc + call .printHexBC + ld c, #6 + rst #0x30 ; .MemcpySmall + pop bc + call .printHexBC + ld a, #0x20 + ld (hl+), a + ld (hl+), a + ld (hl+), a + + ; Now, the two memory dumps +.writeDump: + ld a, l + add a, #(SCRN_VX_B - SCRN_X_B - 1) + ld l, a + ld c, #4 + rst #0x30 ; .MemcpySmall + pop bc + push bc + call .printHexBC + ld de, #.viewStr + ld c, #7 + rst #0x30 ; .MemcpySmall + pop de + call .printDump + ld de, #.spStr + bit #7, l + jr z, .writeDump + + ld de, #.hwRegsStrs + ld l, #<vCrashDumpScreenRow14 + ld c, #6 + rst #0x30 ; .MemcpySmall + ld a, (wCrashLCDC) + call .printHexA + ld c, #4 + rst #0x30 ; .MemcpySmall + ldh a, (.KEY1) + call .printHexA + ld c, #4 + rst #0x30 ; .MemcpySmall + ld a, (wCrashIE) + call .printHexA + ld (hl), #0x20 ; " " + + ld l, #<vCrashDumpScreenRow15 + ld c, #7 + rst #0x30 ; .MemcpySmall +.writeBank: + ld a, #0x20 ; " " + ld (hl+), a + ld a, (de) + inc de + ld (hl+), a + cp #0x20 ; " " + jr z, .banksDone + ld a, (de) + inc de + ld c, a + ld a, (de) + inc de + ld b, a + ld a, (bc) + call .printHexA + jr .writeBank +.banksDone: + + ; Start displaying + ld a, #(LCDCF_ON | LCDCF_BG9C00 | LCDCF_BGON) + ldh (.LCDC), a + +.loop: + ; The code never lags, and IE is equal to IEF_VBLANK + xor a + ldh (.IF), a + halt + + jr .loop + +.printHexBC: + call .printHexB + ld a, c +.printHexA: + ld b, a +.printHexB: + ld a, b + and #0xF0 + swap a + add a, #0x30 + cp #0x3a + jr c, 1$ + add a, #(0x41 - 0x3a) +1$: ld (hl+), a + ld a, b + and #0x0F + add a, #0x30 + cp #0x3a + jr c, 2$ + add a, #(0x41 - 0x3a) +2$: ld (hl+), a + ret + +.printDump: + ld b, d + ld c, e + call .printHexBC + ld a, #0x20 ; " " + ld (hl+), a + ld (hl+), a + ld a, e + sub #8 + ld e, a + ld a, d + sbc #0 + ld d, a +.writeDumpLine: + ld a, l + add a, #(SCRN_VX_B - SCRN_X_B - 1) + ld l, a + ld a, #0x20 ; " " + ld (hl+), a +.writeDumpWord: + ld a, (de) + inc de + call .printHexA + ld a, (de) + inc de + call .printHexA + ld a, #0x20 ; " " + ld (hl+), a + bit 4, l + jr nz, .writeDumpWord + ld a, l + and #0x7F + jr nz, .writeDumpLine + ret + +loadfont: + xor a + cpl + ld hl, #0x9000 + ld c, #16 + rst #0x28 ; .MemsetSmall + ld hl, #(0x9000 + ' ' * 16) + ld c, #16 + rst #0x28 ; .MemsetSmall + + ld de, #(_font_ibm + 2 + '0') ; recode table + ld hl, #(0x9000 + '0' * 16) ; destination + push hl + ld c, #(16 * 3) +1$: + ld a, (de) + inc de + push de + + swap a + ld l, a + and #0x0f + ld h, a + ld a, l + and #0xf0 + srl h + rra + ld l, a + ld de, #(_font_ibm + 2 + 128) + add hl, de + + ld d, h + ld e, l + + ldhl sp, #2 + ld a, (hl+) + ld h, (hl) + ld l, a + + ld b, #8 +2$: + ld a, (de) + cpl + inc de + ld (hl+), a + ld (hl+), a + + dec b + jr nz, 2$ + + ld d, h + ld a, l + ldhl sp, #2 + ld (hl+), a + ld (hl), d + + pop de + + dec c + jr nz, 1$ + + add sp, #2 + ret + +.header: + ; 0123456789ABCDEFGHI 19 chars + .ascii "KERNEL PANIC PLEASE" + .ascii "SEND A CLEAR PIC OF" + .ascii "THIS SCREEN TO DEVS" + .ascii " AF:" + .ascii " MODEL:" + .ascii " BC:" + .ascii " DE:" + .ascii " HL:" +.viewStr: + .ascii " VIEW:" +.spStr: + .ascii " SP:" +.hwRegsStrs: + .ascii " LCDC:" + .ascii " K1:" + .ascii " IE:" + .ascii " BANK:" + .ascii "R" + .dw __current_bank + .ascii "V" + .dw vCrashVBK + .ascii "W" + .db .SVBK, 0xff + .ascii " " + + + .area _DATA + +wCrashA: + .ds 1 ; We need at least one working register, and A allows accessing memory +wCrashIE: + .ds 1 +wCrashLCDC: + .ds 1 + + + .area _CRASH_SCRATCH(ABS) + + .org 0x9C00 + + ; Put the crash dump screen at the bottom-right of the 9C00 tilemap, since that tends to be unused space + .ds SCRN_VX_B * (SCRN_VY_B - SCRN_Y_B - 2) ; 2 rows reserved as scratch space + + .ds SCRN_X_B ; Try not to overwrite the window area + .ds 2 * 1 ; Free stack entries (we spill into the above by 1 entry, though :/) + ; These are the initial values of the registers + ; They are popped off the stack when printed, freeing up stack space + +vCrashAF: + .ds 2 +vCrashBC: + .ds 2 +vCrashDE: + .ds 2 +vCrashHL: + .ds 2 +vCrashSP: + .ds 2 + + .ds SCRN_X_B +vHeldKeys: + .ds 1 ; Keys held on previous frame +vUnlockCounter: + .ds 1 ; How many frames until dumps are "unlocked" +vWhichDump: + .ds 1 +vDumpHL: + .ds 2 +vDumpSP: + .ds 2 +vCrashVBK: + .ds 1 + .ds 4 ; Unused + + .ds SCRN_VX_B - SCRN_X_B - 1 +vCrashDumpScreen: +vCrashDumpScreenRow0 = vCrashDumpScreen + 1 * SCRN_VX_B +vCrashDumpScreenRow1 = vCrashDumpScreen + 2 * SCRN_VX_B +vCrashDumpScreenRow2 = vCrashDumpScreen + 3 * SCRN_VX_B +vCrashDumpScreenRow3 = vCrashDumpScreen + 4 * SCRN_VX_B +vCrashDumpScreenRow4 = vCrashDumpScreen + 5 * SCRN_VX_B +vCrashDumpScreenRow5 = vCrashDumpScreen + 6 * SCRN_VX_B +vCrashDumpScreenRow6 = vCrashDumpScreen + 7 * SCRN_VX_B +vCrashDumpScreenRow7 = vCrashDumpScreen + 8 * SCRN_VX_B +vCrashDumpScreenRow8 = vCrashDumpScreen + 9 * SCRN_VX_B +vCrashDumpScreenRow9 = vCrashDumpScreen + 10 * SCRN_VX_B +vCrashDumpScreenRow10 = vCrashDumpScreen + 11 * SCRN_VX_B +vCrashDumpScreenRow11 = vCrashDumpScreen + 12 * SCRN_VX_B +vCrashDumpScreenRow12 = vCrashDumpScreen + 13 * SCRN_VX_B +vCrashDumpScreenRow13 = vCrashDumpScreen + 14 * SCRN_VX_B +vCrashDumpScreenRow14 = vCrashDumpScreen + 15 * SCRN_VX_B +vCrashDumpScreenRow15 = vCrashDumpScreen + 16 * SCRN_VX_B +vCrashDumpScreenRow16 = vCrashDumpScreen + 17 * SCRN_VX_B +vCrashDumpScreenRow17 = vCrashDumpScreen + 18 * SCRN_VX_B diff --git a/gbdk-lib/libc/targets/gbz80/duck/crt0.s b/gbdk-lib/libc/targets/gbz80/duck/crt0.s @@ -0,0 +1,468 @@ + .include "global.s" + + ;; **************************************** + ;; Beginning of module + ;; BANKED: checked + .title "Runtime" + .module Runtime + .area _HEADER (ABS) + + ;; RST vectors + .org 0x00 ; MEGADUCK entry point/reset + JP .code_start + +; .org 0x08 ; --profile handler utilized by bgb_emu.h + +; .org 0x10 ; empty + +; .org 0x18 ; empty + + .org 0x20 ; RST 0x20 == call HL +.call_hl:: + JP (HL) + + .org 0x28 ; zero up to 256 bytes in C pointed by HL +.MemsetSmall:: + LD (HL+),A + DEC C + JR NZ,.MemsetSmall + ret + + .org 0x30 ; copy up to 256 bytes in C from DE to HL +.MemcpySmall:: + LD A, (DE) + LD (HL+), A + INC DE + DEC C + JR NZ,.MemcpySmall + RET + +; .org 0x38 ; crash handler utilized by crash_handler.h + + ;; Hardware interrupt vectors + .org 0x40 ; VBL +.int_VBL: + PUSH AF + PUSH HL + LD HL,#.int_0x40 + JP .int + +; .org 0x48 ; LCD + +; .org 0x50 ; TIM + +; .org 0x58 ; SIO + +; .org 0x60 ; JOY + +; .org 0x70 + ;; space for drawing.s bit table + + .org 0x80 +.int:: + PUSH BC + PUSH DE +1$: + LD A,(HL+) + OR (HL) + JR Z,.int_tail + PUSH HL + LD A,(HL-) + LD L,(HL) + LD H,A + RST 0x20 ; .call_hl + POP HL + INC HL + JR 1$ +_wait_int_handler:: + ADD SP,#4 +.int_tail: + POP DE + POP BC + POP HL + + ;; we return at least at the beginning of mode 2 + WAIT_STAT + + POP AF + RETI + + ;; VBlank default interrupt routine +__standard_VBL_handler:: +.std_vbl: + LD HL,#.sys_time + INC (HL) + JR NZ,2$ + INC HL + INC (HL) +2$: + CALL .refresh_OAM + + LD A, #1 + LDH (.vbl_done),A + RET + +_refresh_OAM:: + LD HL, #((.refresh_OAM_DMA - .start_refresh_OAM) + .refresh_OAM) + WAIT_STAT + LD A, #>_shadow_OAM + JP (HL) + +.clear_WRAM: + PUSH DE + XOR A + LD BC, #l__DATA + LD HL, #s__DATA + CALL .memset_simple + + LD A, #>_shadow_OAM + LDH (__shadow_OAM_base), A + LD H, A + XOR A + LD L, A + LD C, #(40 << 2) ; 40 entries 4 bytes each + RST 0x28 + POP DE + RET + + .org 0x150 + + ;; soft reset: falldown to .code_start +.reset:: +_reset:: + + ;; Initialization code +.code_start:: + DI ; Disable interrupts + ;; Initialize the stack + LD SP, #.STACK + + CALL .clear_WRAM + +; LD (.mode),A ; Clearing (.mode) is performed when clearing RAM + + ;; Store CPU type + LD A, #.DMG_TYPE ; MEGADUCK is always a DMG + LD (__cpu), A + XOR A + LD (__is_GBA), A ; and it is never GBA + + ;; Turn the screen off + CALL .display_off + + XOR A + ;; Initialize the display + LDH (.SCY),A + LDH (.SCX),A + LDH (.STAT),A + LDH (.WY),A + LD A,#0x07 + LDH (.WX),A + + ;; Copy refresh_OAM routine to HRAM + LD DE,#.start_refresh_OAM ; source + LD HL,#.refresh_OAM ; dest + LD C,#(.end_refresh_OAM - .start_refresh_OAM) ; size + RST 0x30 ; call .MemcpySmall + + ;; Clear the OAM by calling refresh_OAM + CALL .refresh_OAM + + ;; Install interrupt routines + LD BC,#.std_vbl + CALL .add_VBL + + ;; Standard color palettes + LD A,#0b11100100 ; Grey 3 = 11 (Black) + ; Grey 2 = 10 (Dark grey) + ; Grey 1 = 01 (Light grey) + ; Grey 0 = 00 (Transparent) + LDH (.BGP),A + LDH (.OBP0),A + LD A,#0b00011011 + LDH (.OBP1),A + + ;; Turn the screen on + LD A,#(LCDCF_ON | LCDCF_WIN9C00 | LCDCF_WINOFF | LCDCF_BG8800 | LCDCF_BG9800 | LCDCF_OBJ8 | LCDCF_OBJOFF | LCDCF_BGOFF) + LDH (.LCDC),A + XOR A + LDH (.IF),A + LD A,#.VBL_IFLAG ; switch on VBlank interrupt only + LDH (.IE),A + + LDH (__current_bank),A ; current bank is 1 at startup + + XOR A + + LD HL,#.sys_time + LD (HL+),A + LD (HL),A + + LDH (.NR52),A ; Turn sound off + + CALL gsinit + + EI ; Enable interrupts + + ;; Call the main function + CALL _main +_exit:: +99$: + HALT + NOP + JR 99$ ; Wait forever + +_set_interrupts:: + DI + LDA HL,2(SP) ; Skip return address + XOR A + LDH (.IF),A ; Clear pending interrupts + LD A,(HL) + EI ; Enable interrupts + LDH (.IE),A ; interrupts are still disabled here + RET + + ;; Copy OAM data to OAM RAM +.start_refresh_OAM: + LDH A,(__shadow_OAM_base) + OR A + RET Z +.refresh_OAM_DMA: + LDH (.DMA),A ; Put A into DMA registers + LD A,#0x28 ; We need to wait 160 ns +1$: + DEC A + JR NZ,1$ + RET +.end_refresh_OAM: + + .org .MODE_TABLE + ;; Jump table for modes + RET + + ;; **************************************** + + ;; Ordering of segments for the linker + ;; Code that really needs to be in bank 0 + .area _HOME + ;; Similar to _HOME + .area _BASE + ;; Code + .area _CODE + ;; #pragma bank 0 workaround + .area _CODE_0 + ;; Constant data + .area _LIT +; ;; since _CODE_1 area base address is pre-defined in the linker from 0x4000, +; ;; that moves initializer code and tables out of bank 0 +; .area _CODE_1 + ;; Constant data, used to init _DATA + .area _INITIALIZER + ;; Code, used to init _DATA + .area _GSINIT + .area _GSFINAL + ;; Uninitialised ram data + .area _DATA + .area _BSS + ;; Initialised in ram data + .area _INITIALIZED + ;; For malloc + .area _HEAP + + .area _DATA +__cpu:: + .ds 0x01 ; GB type (GB, PGB, CGB) +__is_GBA:: + .ds 0x01 ; detect GBA +.mode:: + .ds 0x01 ; Current mode +.sys_time:: +_sys_time:: + .ds 0x02 ; System time in VBL units +.int_0x40:: + .blkw 0x0A ; 4 interrupt handlers (built-in + user-defined) + + .area _HRAM (ABS) + + .org 0xFF90 +__current_bank:: ; Current bank + .ds 0x01 +.vbl_done: + .ds 0x01 ; Is VBL interrupt finished? +__shadow_OAM_base:: + .ds 0x01 + + ;; Runtime library + .area _GSINIT +gsinit:: + ;; initialize static storage variables + LD BC, #l__INITIALIZER + LD HL, #s__INITIALIZER + LD DE, #s__INITIALIZED + call .memcpy_simple + + .area _GSFINAL + ret + + .area _HOME + + ;; fills memory at HL of length BC with A, clobbers DE +.memset_simple:: + LD E, A + LD A, B + OR C + RET Z + LD (HL), E + DEC BC + LD D, H + LD E, L + INC DE + + ;; copies BC bytes from HL into DE +.memcpy_simple:: + LD A, B + OR C + RET Z + + SRL B + RR C + JR NC,3$ + LD A, (HL+) + LD (DE), A + INC DE +3$: + INC B + INC C + JR 2$ +1$: + LD A, (HL+) + LD (DE), A + INC DE + LD A, (HL+) + LD (DE), A + INC DE +2$: + DEC C + JR NZ,1$ + DEC B + JR NZ,1$ +4$: + RET + + ;; Remove interrupt routine in BC from the VBL interrupt list + ;; falldown to .remove_int +.remove_VBL:: + LD HL,#.int_0x40 + + ;; Remove interrupt BC from interrupt list HL if it exists + ;; Abort if a 0000 is found (end of list) +.remove_int:: +1$: + LD A,(HL+) + LD E,A + LD D,(HL) + INC HL + OR D + RET Z ; No interrupt found + + LD A,E + CP C + JR NZ,1$ + LD A,D + CP B + JR NZ,1$ + + LD D,H + LD E,L + DEC DE + DEC DE + + ;; Now do a memcpy from here until the end of the list +2$: + LD A,(HL+) + LD (DE),A + LD B,A + INC DE + LD A,(HL+) + LD (DE),A + INC DE + OR B + RET Z + JR 2$ + + ;; Add interrupt routine in BC to the VBL interrupt list + ;; falldown to .add_int +.add_VBL:: + LD HL,#.int_0x40 + + ;; Add interrupt routine in BC to the interrupt list in HL +.add_int:: +1$: + LD A,(HL+) + OR (HL) + JR Z,2$ + INC HL + JR 1$ +2$: + LD A,B + LD (HL-),A + LD (HL),C + RET + + ;; Wait for VBL interrupt to be finished +.wait_vbl_done:: +_wait_vbl_done:: + ;; Check if the screen is on + LDH A,(.LCDC) + AND #LCDCF_ON + RET Z ; Return if screen is off + XOR A + LDH (.vbl_done),A ; Clear any previous sets of vbl_done +1$: + HALT ; Wait for any interrupt + NOP ; HALT sometimes skips the next instruction + LDH A,(.vbl_done) ; Was it a VBlank interrupt? + ;; Warning: we may lose a VBlank interrupt, if it occurs now + OR A + JR Z,1$ ; No: back to sleep! + RET + +.display_off:: +_display_off:: + ;; Check if the screen is on + LDH A,(.LCDC) + AND #LCDCF_ON + RET Z ; Return if screen is off +1$: ; We wait for the *NEXT* VBL + LDH A,(.LY) + CP #0x92 ; Smaller than or equal to 0x91? + JR NC,1$ ; Loop until smaller than or equal to 0x91 +2$: + LDH A,(.LY) + CP #0x91 ; Bigger than 0x90? + JR C,2$ ; Loop until bigger than 0x90 + + LDH A,(.LCDC) + AND #~LCDCF_ON + LDH (.LCDC),A ; Turn off screen + RET + +_remove_VBL:: + PUSH BC + LDA HL,4(SP) ; Skip return address and registers + LD A,(HL+) + LD C,A + LD B,(HL) + CALL .remove_VBL + POP BC + RET + +_add_VBL:: + PUSH BC + LDA HL, 4(SP) ; Skip return address and registers + LD A,(HL+) + LD C,A + LD B,(HL) + CALL .add_VBL + POP BC + RET diff --git a/gbdk-lib/libc/targets/gbz80/duck/global.s b/gbdk-lib/libc/targets/gbz80/duck/global.s @@ -0,0 +1,509 @@ + .NEAR_CALLS = 1 ; <near_calls> - tag so that sed can change this + + ;; Changed by astorgb.pl to 1 + __RGBDS__ = 0 + + _VRAM = 0x8000 ; $8000->$9FFF + _VRAM8000 = 0x8000 + _VRAM8800 = 0x8800 + _VRAM9000 = 0x9000 + _SCRN0 = 0x9800 ; $9800->$9BFF + _SCRN1 = 0x9C00 ; $9C00->$9FFF + _SRAM = 0xA000 ; $A000->$BFFF + _RAM = 0xC000 ; $C000->$CFFF / $C000->$DFFF + _RAMBANK = 0xD000 ; $D000->$DFFF + _OAMRAM = 0xFE00 ; $FE00->$FE9F + _IO = 0xFF00 ; $FF00->$FF7F,$FFFF + _AUD3WAVERAM = 0xFF30 ; $FF30->$FF3F + _HRAM = 0xFF80 ; $FF80->$FFFE + + ;; MBC Equates + + .MBC1_ROM_PAGE = 0x2000 ; Address to write to for MBC1 switching + .MBC_ROM_PAGE = 0x0001 ; Default platform MBC rom switching address + + rRAMG = 0x0000 ; $0000->$1fff + rROMB0 = 0x0001 ; $2000->$2fff + rROMB1 = 0x3000 ; $3000->$3fff - If more than 256 ROM banks are present. + rRAMB = 0x4000 ; $4000->$5fff - Bit 3 enables rumble (if present) + + ;; Keypad + .START = 0x80 + .SELECT = 0x40 + .B = 0x20 + .A = 0x10 + .DOWN = 0x08 + .UP = 0x04 + .LEFT = 0x02 + .RIGHT = 0x01 + + .P14 = 0x10 + .P15 = 0x20 + + ;; Screen dimensions + .MAXCURSPOSX = 0x13 ; In tiles + .MAXCURSPOSY = 0x11 + + .SCREENWIDTH = 0xA0 + .SCREENHEIGHT = 0x90 + .MINWNDPOSX = 0x07 + .MINWNDPOSY = 0x00 + .MAXWNDPOSX = 0xA6 + .MAXWNDPOSY = 0x8F + + ;; Hardware registers + + .P1 = 0x00 ; Joystick: 1.1.P15.P14.P13.P12.P11.P10 + rP1 = 0xFF00 + + P1F_5 = 0b00100000 ; P15 out port, set to 0 to get buttons + P1F_4 = 0b00010000 ; P14 out port, set to 0 to get dpad + P1F_3 = 0b00001000 ; P13 in port + P1F_2 = 0b00000100 ; P12 in port + P1F_1 = 0b00000010 ; P11 in port + P1F_0 = 0b00000001 ; P10 in port + + P1F_GET_DPAD = 0b00100000 + P1F_GET_BTN = 0b00010000 + P1F_GET_NONE = 0b00110000 + + .SB = 0x01 ; Serial IO data buffer + rSB = 0xFF01 + + .SC = 0x02 ; Serial IO control register + rSC = 0xFF02 + + .DIV = 0x04 ; Divider register + rDIV = 0xFF04 + + .TIMA = 0x05 ; Timer counter + rTIMA = 0xFF05 + + .TMA = 0x06 ; Timer modulo + rTMA = 0xFF06 + + .TAC = 0x07 ; Timer control + rTAC = 0xFF07 + + TACF_START = 0b00000100 + TACF_STOP = 0b00000000 + TACF_4KHZ = 0b00000000 + TACF_16KHZ = 0b00000011 + TACF_65KHZ = 0b00000010 + TACF_262KHZ = 0b00000001 + + .IF = 0x0F ; Interrupt flags: 0.0.0.JST.SIO.TIM.LCD.VBL + rIF = 0xFF0F + + .NR10 = 0x20 ; Sound register + rNR10 = 0xFF20 + rAUD1SWEEP = 0xFF20 + + AUD1SWEEP_UP = 0b00000000 + AUD1SWEEP_DOWN = 0b00001000 + + .NR11 = 0x22 ; Sound register + rNR11 = 0xFF22 + rAUD1LEN = 0xFF22 + + .NR12 = 0x21 ; Sound register + rNR12 = 0xFF21 + rAUD1ENV = 0xFF21 + + .NR13 = 0x23 ; Sound register + rNR13 = 0xFF23 + rAUD1LOW = 0xFF23 + + .NR14 = 0x24 ; Sound register + rNR14 = 0xFF24 + rAUD1HIGH = 0xFF24 + + .NR21 = 0x26 ; Sound register + rNR21 = 0xFF26 + rAUD2LEN = 0xFF26 + + .NR22 = 0x28 ; Sound register + rNR22 = 0xFF28 + rAUD2ENV = 0xFF28 + + .NR23 = 0x27 ; Sound register + rNR23 = 0xFF27 + rAUD2LOW = 0xFF27 + + .NR24 = 0x29 ; Sound register + rNR24 = 0xFF29 + rAUD2HIGH = 0xFF29 + + .NR30 = 0x2A ; Sound register + rNR30 = 0xFF2A + rAUD3ENA = 0xFF2A + + .NR31 = 0x2B ; Sound register + rNR31 = 0xFF2B + rAUD3LEN = 0xFF2B + + .NR32 = 0x2C ; Sound register + rNR32 = 0xFF2C + rAUD3LEVEL = 0xFF2C + + .NR33 = 0x2E ; Sound register + rNR33 = 0xFF2E + rAUD3LOW = 0xFF2E + + .NR34 = 0x2D ; Sound register + rNR34 = 0xFF2D + rAUD3HIGH = 0xFF2D + + .NR41 = 0x40 ; Sound register + rNR41 = 0xFF40 + rAUD4LEN = 0xFF40 + + .NR42 = 0x42 ; Sound register + rNR42 = 0xFF42 + rAUD4ENV = 0xFF42 + + .NR43 = 0x41 ; Sound register + rNR43 = 0xFF41 + rAUD4POLY = 0xFF41 + + .NR44 = 0x43 ; Sound register + rNR44 = 0xFF43 + rAUD4GO = 0xFF43 + + .NR50 = 0x44 ; Sound register + rNR50 = 0xFF44 + rAUDVOL = 0xFF44 + + AUDVOL_VIN_LEFT = 0b10000000 ; SO2 + AUDVOL_VIN_RIGHT = 0b00001000 ; SO1 + + .NR51 = 0x46 ; Sound register + rNR51 = 0xFF46 + rAUDTERM = 0xFF46 + + AUDTERM_4_LEFT = 0b10000000 + AUDTERM_3_LEFT = 0b01000000 + AUDTERM_2_LEFT = 0b00100000 + AUDTERM_1_LEFT = 0b00010000 + AUDTERM_4_RIGHT = 0b00001000 + AUDTERM_3_RIGHT = 0b00000100 + AUDTERM_2_RIGHT = 0b00000010 + AUDTERM_1_RIGHT = 0b00000001 + + .NR52 = 0x45 ; Sound register + rNR52 = 0xFF45 + rAUDENA = 0xFF45 + + AUDENA_ON = 0b10000000 + AUDENA_OFF = 0b00000000 ; sets all audio regs to 0! + + .LCDC = 0x10 ; LCD control + rLCDC = 0xFF10 + + LCDCF_OFF = 0b00000000 ; LCD Control Operation + LCDCF_ON = 0b10000000 ; LCD Control Operation + LCDCF_WIN9800 = 0b00000000 ; Window Tile Map Display Select + LCDCF_WIN9C00 = 0b00001000 ; Window Tile Map Display Select + LCDCF_WINOFF = 0b00000000 ; Window Display + LCDCF_WINON = 0b00100000 ; Window Display + LCDCF_BG8800 = 0b00000000 ; BG & Window Tile Data Select + LCDCF_BG8000 = 0b00010000 ; BG & Window Tile Data Select + LCDCF_BG9800 = 0b00000000 ; BG Tile Map Display Select + LCDCF_BG9C00 = 0b00000100 ; BG Tile Map Display Select + LCDCF_OBJ8 = 0b00000000 ; OBJ Construction + LCDCF_OBJ16 = 0b00000010 ; OBJ Construction + LCDCF_OBJOFF = 0b00000000 ; OBJ Display + LCDCF_OBJON = 0b00000001 ; OBJ Display + LCDCF_BGOFF = 0b00000000 ; BG Display + LCDCF_BGON = 0b01000000 ; BG Display + LCDCF_B_ON = 7 + LCDCF_B_WIN9C00 = 3 + LCDCF_B_WINON = 5 + LCDCF_B_BG8000 = 4 + LCDCF_B_BG9C00 = 2 + LCDCF_B_OBJ16 = 1 + LCDCF_B_OBJON = 0 + LCDCF_B_BGON = 6 + + .STAT = 0x11 ; LCD status + rSTAT = 0xFF11 + + STATF_LYC = 0b01000000 ; LYC=LY Coincidence (Selectable) + STATF_MODE10 = 0b00100000 ; Mode 10 + STATF_MODE01 = 0b00010000 ; Mode 01 (V-Blank) + STATF_MODE00 = 0b00001000 ; Mode 00 (H-Blank) + STATF_LYCF = 0b00000100 ; Coincidence Flag + STATF_HBL = 0b00000000 ; H-Blank + STATF_VBL = 0b00000001 ; V-Blank + STATF_OAM = 0b00000010 ; OAM-RAM is used by system + STATF_LCD = 0b00000011 ; Both OAM and VRAM used by system + STATF_BUSY = 0b00000010 ; When set, VRAM access is unsafe + STATF_B_LYC = 6 + STATF_B_MODE10 = 5 + STATF_B_MODE01 = 4 + STATF_B_MODE00 = 3 + STATF_B_LYCF = 2 + STATF_B_VBL = 0 + STATF_B_OAM = 1 + STATF_B_BUSY = 1 + + .SCY = 0x12 ; Scroll Y + rSCY = 0xFF12 + + .SCX = 0x13 ; Scroll X + rSCX = 0xFF13 + + .LY = 0x18 ; LCDC Y-coordinate + rLY = 0xFF18 + + .LYC = 0x19 ; LY compare + rLYC = 0xFF19 + + .DMA = 0x1A ; DMA transfer + rDMA = 0xFF1A + + .BGP = 0x1B ; BG palette data + rBGP = 0xFF1B + + .OBP0 = 0x14 ; OBJ palette 0 data + rOBP0 = 0xFF14 + + .OBP1 = 0x15 ; OBJ palette 1 data + rOBP1 = 0xFF15 + + .WY = 0x16 ; Window Y coordinate + rWY = 0xFF16 + + .WX = 0x17 ; Window X coordinate + rWX = 0xFF17 + + .KEY1 = 0x4D ; CPU speed + rKEY1 = 0xFF4D + rSPD = 0xFF4D + + KEY1F_DBLSPEED = 0b10000000 ; 0=Normal Speed, 1=Double Speed (R) + KEY1F_PREPARE = 0b00000001 ; 0=No, 1=Prepare (R/W) + + .VBK = 0x4F ; VRAM bank + rVBK = 0xFF4F + + .HDMA1 = 0x51 ; DMA control 1 + rHDMA1 = 0xFF51 + + .HDMA2 = 0x52 ; DMA control 2 + rHDMA2 = 0xFF52 + + .HDMA3 = 0x53 ; DMA control 3 + rHDMA3 = 0xFF53 + + .HDMA4 = 0x54 ; DMA control 4 + rHDMA4 = 0xFF54 + + .HDMA5 = 0x55 ; DMA control 5 + rHDMA5 = 0xFF55 + + HDMA5F_MODE_GP = 0b00000000 ; General Purpose DMA (W) + HDMA5F_MODE_HBL = 0b10000000 ; HBlank DMA (W) + + HDMA5F_BUSY = 0b10000000 ; 0=Busy (DMA still in progress), 1=Transfer complete (R) + + .RP = 0x56 ; IR port + rRP = 0xFF56 + + RPF_ENREAD = 0b11000000 + RPF_DATAIN = 0b00000010 ; 0=Receiving IR Signal, 1=Normal + RPF_WRITE_HI = 0b00000001 + RPF_WRITE_LO = 0b00000000 + + .BCPS = 0x68 ; BG color palette specification + rBCPS = 0xFF68 + + BCPSF_AUTOINC = 0b10000000 ; Auto Increment (0=Disabled, 1=Increment after Writing) + + .BCPD = 0x69 ; BG color palette data + rBCPD = 0xFF69 + + .OCPS = 0x6A ; OBJ color palette specification + rOCPS = 0xFF6A + + OCPSF_AUTOINC = 0b10000000 ; Auto Increment (0=Disabled, 1=Increment after Writing) + + .OCPD = 0x6B ; OBJ color palette data + rOCPD = 0xFF6B + + .SVBK = 0x70 ; WRAM bank + rSVBK = 0xFF70 + rSMBK = 0xFF70 + + rPCM12 = 0xFF76 + + rPCM34 = 0xFF77 + + .IE = 0xFF ; Interrupt enable + rIE = 0xFFFF + + .VBL_IFLAG = 0x01 + .LCD_IFLAG = 0x02 + .TIM_IFLAG = 0x04 + .SIO_IFLAG = 0x08 + .JOY_IFLAG = 0x10 + + IEF_HILO = 0b00010000 ; Transition from High to Low of Pin number P10-P13 + IEF_SERIAL = 0b00001000 ; Serial I/O transfer end + IEF_TIMER = 0b00000100 ; Timer Overflow + IEF_STAT = 0b00000010 ; STAT + IEF_VBLANK = 0b00000001 ; V-Blank + + ;; Flags common to multiple sound channels + + AUDLEN_DUTY_12_5 = 0b00000000 ; 12.5% + AUDLEN_DUTY_25 = 0b01000000 ; 25% + AUDLEN_DUTY_50 = 0b10000000 ; 50% + AUDLEN_DUTY_75 = 0b11000000 ; 75% + + AUDENV_UP = 0b00001000 + AUDENV_DOWN = 0b00000000 + + AUDHIGH_RESTART = 0b10000000 + AUDHIGH_LENGTH_ON = 0b01000000 + AUDHIGH_LENGTH_OFF = 0b00000000 + + ;; OAM related constants + + OAM_COUNT = 40 ; number of OAM entries in OAM RAM + + OAMF_PRI = 0b10000000 ; Priority + OAMF_YFLIP = 0b01000000 ; Y flip + OAMF_XFLIP = 0b00100000 ; X flip + OAMF_PAL0 = 0b00000000 ; Palette number; 0,1 (DMG) + OAMF_PAL1 = 0b00010000 ; Palette number; 0,1 (DMG) + OAMF_BANK0 = 0b00000000 ; Bank number; 0,1 (GBC) + OAMF_BANK1 = 0b00001000 ; Bank number; 0,1 (GBC) + + OAMF_PALMASK = 0b00000111 ; Palette (GBC) + + OAMB_PRI = 7 ; Priority + OAMB_YFLIP = 6 ; Y flip + OAMB_XFLIP = 5 ; X flip + OAMB_PAL1 = 4 ; Palette number; 0,1 (DMG) + OAMB_BANK1 = 3 ; Bank number; 0,1 (GBC) + + ;; CPU detection + .DMG_TYPE = 0x01 ; Original GB or Super GB + .MGB_TYPE = 0xFF ; Pocket GB or Super GB 2 + .CGB_TYPE = 0x11 ; Color GB + + ;; GBDK library screen modes + + .G_MODE = 0x01 ; Graphic mode + .T_MODE = 0x02 ; Text mode (bit 2) + .T_MODE_OUT = 0x02 ; Text mode output only + .T_MODE_INOUT = 0x03 ; Text mode with input + .M_NO_SCROLL = 0x04 ; Disables scrolling of the screen in text mode + .M_NO_INTERP = 0x08 ; Disables special character interpretation + + ;; Status codes for IO + .IO_IDLE = 0x00 + .IO_SENDING = 0x01 + .IO_RECEIVING = 0x02 + .IO_ERROR = 0x04 + + ;; Type of IO data + .DT_IDLE = 0x66 + .DT_RECEIVING = 0x55 + + ;; Table of routines for modes + .MODE_TABLE = 0x01E0 + + ;; C related + ;; Overheap of a banked call. Used for parameters + ;; = ret + real ret + bank + + .if .NEAR_CALLS + .BANKOV = 2 + + .else + .BANKOV = 6 + + .endif + + .globl __current_bank + .globl __shadow_OAM_base + + ;; Global variables + .globl .mode + + .globl __cpu + .globl __is_GBA + + ;; Global routines +; .globl .set_mode ;; don't link mode.o by default + + .globl .reset + + .globl .display_off + + .globl .wait_vbl_done + + ;; Interrupt routines + .globl .add_VBL +; .globl .add_LCD ;; don't link LCD.o by default +; .globl .add_TIM ;; don't link TIM.o by default +; .globl .add_SIO ;; don't link serial.o by default +; .globl .add_JOY ;; don't link JOY.o by default + + ;; Symbols defined at link time + .globl .STACK + .globl _shadow_OAM + .globl .refresh_OAM + + ;; Main user routine + .globl _main + + ;; Macro definitions + +.macro WAIT_STAT ?lbl +lbl: LDH A, (.STAT) + AND #STATF_BUSY ; Check if in LCD modes 0 or 1 + JR NZ, lbl +.endm + +.macro ADD_A_REG16 regH regL + ADD regL + LD regL, A + ADC regH + SUB regL + LD regH, A +.endm + +.macro SIGNED_ADD_A_REG16 regH regL ?lbl + ; If A is negative, we need to subtract 1 from upper byte of 16-bit value + BIT 7, A ; set z if a signed bit is 0 + JR Z, lbl ; if z is set jump to positive + dec regH ; if negative decrement upper byte +lbl: + ADD_A_REG16 regH, regL +.endm + +.macro SIGNED_SUB_A_REG16 regH regL ?lbl + ; negate A then add to 16-bit value + CPL + INC A + SIGNED_ADD_A_REG16 regH, regL +.endm + +.macro MUL_DE_BY_A_RET_HL ?lbl1 ?lbl2 ?lbl3 + ; Multiply DE by A, return result in HL; preserves: BC + LD HL, #0 +lbl1: + SRL A + JR NC, lbl2 + ADD HL, DE +lbl2: + JR Z, lbl3 + SLA E + RL D + JR lbl1 +lbl3: +.endm + diff --git a/gbdk-lib/libc/targets/gbz80/duck/sfr.s b/gbdk-lib/libc/targets/gbz80/duck/sfr.s @@ -0,0 +1,111 @@ +__VRAM = 0x8000 +__VRAM8000 = 0x8000 +__VRAM8800 = 0x8800 +__VRAM9000 = 0x9000 +__SCRN0 = 0x9800 +__SCRN1 = 0x9C00 +__SRAM = 0xA000 +__RAM = 0xC000 +__RAMBANK = 0xD000 +__OAMRAM = 0xFE00 +__IO = 0xFF00 +__AUD3WAVERAM = 0xFF30 +__HRAM = 0xFF80 + +.globl __VRAM, __VRAM8000, __VRAM8800, __VRAM9000, __SCRN0, __SCRN1, __SRAM, __RAM, __RAMBANK, __OAMRAM, __IO, __AUD3WAVERAM, __HRAM + +_rRAMG = 0x0000 +_rROMB0 = 0x0001 +_rROMB1 = 0x3000 +_rRAMB = 0x4000 + +.globl _rRAMG, _rROMB0, _rROMB1, _rRAMB + +_P1_REG = 0xFF00 ; Joystick: 1.1.P15.P14.P13.P12.P11.P10 +_SB_REG = 0xFF01 ; Serial IO data buffer +_SC_REG = 0xFF02 ; Serial IO control register +_DIV_REG = 0xFF04 ; Divider register +_TIMA_REG = 0xFF05 ; Timer counter +_TMA_REG = 0xFF06 ; Timer modulo +_TAC_REG = 0xFF07 ; Timer control +_IF_REG = 0xFF0F ; Interrupt flags: 0.0.0.JOY.SIO.TIM.LCD.VBL +_LCDC_REG = 0xFF10 ; LCD control +_STAT_REG = 0xFF11 ; LCD status +_SCY_REG = 0xFF12 ; Scroll Y +_SCX_REG = 0xFF13 ; Scroll X +_OBP0_REG = 0xFF14 ; OBJ palette 0 data +_OBP1_REG = 0xFF15 ; OBJ palette 1 data +_WY_REG = 0xFF16 ; Window Y coordinate +_WX_REG = 0xFF17 ; Window X coordinate +_LY_REG = 0xFF18 ; LCDC Y-coordinate +_LYC_REG = 0xFF19 ; LY compare +_DMA_REG = 0xFF1A ; DMA transfer +_BGP_REG = 0xFF1B ; BG palette data +_NR10_REG = 0xFF20 ; Sound register +_NR12_REG = 0xFF21 ; Sound register +_NR11_REG = 0xFF22 ; Sound register +_NR13_REG = 0xFF23 ; Sound register +_NR14_REG = 0xFF24 ; Sound register +_NR21_REG = 0xFF26 ; Sound register +_NR23_REG = 0xFF27 ; Sound register +_NR22_REG = 0xFF28 ; Sound register +_NR24_REG = 0xFF29 ; Sound register +_NR30_REG = 0xFF2A ; Sound register +_NR31_REG = 0xFF2B ; Sound register +_NR32_REG = 0xFF2C ; Sound register +_NR34_REG = 0xFF2D ; Sound register +_NR33_REG = 0xFF2E ; Sound register +_NR41_REG = 0xFF40 ; Sound register +_NR43_REG = 0xFF41 ; Sound register +_NR42_REG = 0xFF42 ; Sound register +_NR44_REG = 0xFF43 ; Sound register +_NR50_REG = 0xFF44 ; Sound register +_NR52_REG = 0xFF45 ; Sound register +_NR51_REG = 0xFF46 ; Sound register +_PCM_SAMPLE = 0xFF30 ; PCM wave pattern + +_KEY1_REG = 0xFF4D ; CPU speed +_VBK_REG = 0xFF4F ; VRAM bank +_HDMA1_REG = 0xFF51 ; DMA control 1 +_HDMA2_REG = 0xFF52 ; DMA control 2 +_HDMA3_REG = 0xFF53 ; DMA control 3 +_HDMA4_REG = 0xFF54 ; DMA control 4 +_HDMA5_REG = 0xFF55 ; DMA control 5 +_RP_REG = 0xFF56 ; IR port +_BCPS_REG = 0xFF68 ; BG color palette specification +_BCPD_REG = 0xFF69 ; BG color palette data +_OCPS_REG = 0xFF6A ; OBJ color palette specification +_OCPD_REG = 0xFF6B ; OBJ color palette data +_SVBK_REG = 0xFF70 ; WRAM bank +_PCM12_REG = 0xFF76 ; Sound channel 1&2 PCM amplitude (R) +_PCM34_REG = 0xFF77 ; Sound channel 3&4 PCM amplitude (R) +_IE_REG = 0xFFFF ; Interrupt enable + +.globl _P1_REG +.globl _SB_REG, _SC_REG +.globl _DIV_REG +.globl _TIMA_REG, _TMA_REG, _TAC_REG +.globl _IF_REG +.globl _NR10_REG, _NR11_REG, _NR12_REG, _NR13_REG, _NR14_REG +.globl _NR21_REG, _NR22_REG, _NR23_REG, _NR24_REG +.globl _NR30_REG, _NR31_REG, _NR32_REG, _NR33_REG, _NR34_REG +.globl _NR41_REG, _NR42_REG, _NR43_REG, _NR44_REG +.globl _NR50_REG, _NR51_REG, _NR52_REG +.globl _PCM_SAMPLE +.globl _LCDC_REG +.globl _STAT_REG +.globl _SCY_REG, _SCX_REG +.globl _LY_REG, _LYC_REG +.globl _DMA_REG +.globl _BGP_REG +.globl _OBP0_REG, _OBP1_REG +.globl _WY_REG, _WX_REG +.globl _KEY1_REG +.globl _VBK_REG +.globl _HDMA1_REG, _HDMA2_REG, _HDMA3_REG, _HDMA4_REG, _HDMA5_REG +.globl _RP_REG +.globl _BCPS_REG, _BCPD_REG +.globl _OCPS_REG, _OCPD_REG +.globl _SVBK_REG +.globl _PCM12_REG, _PCM34_REG +.globl _IE_REG + diff --git a/gbdk-lib/libc/targets/gbz80/far_ptr.s b/gbdk-lib/libc/targets/gbz80/far_ptr.s @@ -43,7 +43,7 @@ ___call__banked:: ld L, A ld A, (#___call_banked_bank) ldh (#__current_bank), A - ld (.MBC1_ROM_PAGE),A + ld (.MBC_ROM_PAGE),A jp (HL) 1$: pop AF diff --git a/gbdk-lib/libc/targets/gbz80/crash_handler.s b/gbdk-lib/libc/targets/gbz80/gb/crash_handler.s diff --git a/gbdk-lib/libc/targets/gbz80/gb/global.s b/gbdk-lib/libc/targets/gbz80/gb/global.s @@ -20,6 +20,7 @@ ;; MBC Equates .MBC1_ROM_PAGE = 0x2000 ; Address to write to for MBC1 switching + .MBC_ROM_PAGE = 0x2000 ; Default platform MBC rom switching address rRAMG = 0x0000 ; $0000->$1fff rROMB0 = 0x2000 ; $2000->$2fff diff --git a/gbdk-support/bankpack/obj_data.c b/gbdk-support/bankpack/obj_data.c @@ -56,7 +56,9 @@ void banks_set_platform(char * platform_str) { if (strcmp(platform_str, PLATFORM_STR_GB) == 0) g_platform = PLATFORM_GB; else if (strcmp(platform_str, PLATFORM_STR_AP) == 0) - g_platform = PLATFORM_GB; // AP uses GB platform + g_platform = PLATFORM_GB; // Analogue Pocket uses GB platform + else if (strcmp(platform_str, PLATFORM_STR_DUCK) == 0) + g_platform = PLATFORM_GB; // Megaduck uses GB platform else if (strcmp(platform_str, PLATFORM_STR_SMS) == 0) g_platform = PLATFORM_SMS; else if (strcmp(platform_str, PLATFORM_STR_GG) == 0) diff --git a/gbdk-support/bankpack/obj_data.h b/gbdk-support/bankpack/obj_data.h @@ -18,6 +18,7 @@ #define PLATFORM_STR_GB "gb" #define PLATFORM_STR_AP "ap" // Uses PLATFORM_GB +#define PLATFORM_STR_DUCK "duck" // Uses PLATFORM_GB #define PLATFORM_STR_SMS "sms" #define PLATFORM_STR_GG "gg" // Uses PLATFORM_SMS diff --git a/gbdk-support/lcc/gb.h b/gbdk-support/lcc/gb.h @@ -17,6 +17,7 @@ // ROM file extensions #define EXT_GB ".gb" #define EXT_AP ".pocket" +#define EXT_DUCK ".duck" #define EXT_SMS ".sms" #define EXT_GG ".gg" diff --git a/gbdk-support/lcc/lcc.c b/gbdk-support/lcc/lcc.c @@ -746,7 +746,7 @@ static void help(void) { "-Idir add `dir' to the beginning of the list of #include directories\n", "-K don't run ihxcheck test on linker ihx output\n", "-lx search library `x'\n", -"-m select port and platform: \"-m[port]:[plat]\" ports:gbz80,z80 plats:ap,gb,sms,gg\n", +"-m select port and platform: \"-m[port]:[plat]\" ports:gbz80,z80 plats:ap,duck,gb,sms,gg\n", "-N do not search the standard directories for #include files\n", "-n emit code to check for dereferencing zero pointers\n", "-no-crt do not auto-include the gbdk crt0.o runtime in linker list\n", diff --git a/gbdk-support/lcc/targets.c b/gbdk-support/lcc/targets.c @@ -9,7 +9,7 @@ // // NOTE: Only -g and -b entries are supported by Fixllist() right now -// Game Boy / AP +// Game Boy / Analogue Pocket / Megaduck arg_entry llist0_defaults_gb[] = { {.searchkey= "_shadow_OAM=", .addflag= "-g",.addvalue= "_shadow_OAM=0xC000", .found= false}, {.searchkey= ".STACK=", .addflag= "-g",.addvalue= ".STACK=0xE000", .found= false}, @@ -48,7 +48,7 @@ CLASS classes[] = { "%mkbin% -Z $1 $2 $3", llist0_defaults_gb, ARRAY_LEN(llist0_defaults_gb), }, - // AP + // Analogue Pocket { "gbz80", // port "ap", // plat "ap", // default_plat @@ -63,6 +63,21 @@ CLASS classes[] = { "%mkbin% -Z $1 $2 $3", llist0_defaults_gb, ARRAY_LEN(llist0_defaults_gb), // Use GB linker list defaults }, + // Megaduck + { "gbz80", // port + "duck", // plat + "duck", // default_plat + EXT_DUCK, // ROM file extension + "%cpp% %cppdefault% -DINT_16_BITS $1 $2 $3", + "%includedefault%", + "%com% %comdefault% -Wa%asdefault% -DINT_16_BITS $1 %comflag% $2 -o $3", + "%as_gb% %asdefault% $1 $3 $2", + "%bankpack% $1 $2", + "%ld_gb% -n -i $1 %libs_include% $3 %crt0dir% $2", + "%ihxcheck% $2 $1", + "%mkbin% -Z $1 $2 $3", + llist0_defaults_gb, ARRAY_LEN(llist0_defaults_gb), // Use GB linker list defaults + }, // SMS { "z80", // port
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.