git.y1.nz

gbdk-2020

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

commit bd99d4ce69dcbab46586e1d8f3b055ff5426df07
parent 4ff8549fda7d9262c38f61f2f74c75970706e40a
Author: Toxa <untoxa@mail.ru>
Date:   Mon, 24 Feb 2025 23:02:36 +0300

SMS/GG: Timer interrupt emulation

Diffstat:
Agbdk-lib/examples/cross-platform/irq/Makefile86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Agbdk-lib/examples/cross-platform/irq/Makefile.targets55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Agbdk-lib/examples/cross-platform/irq/src/irq.c68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dgbdk-lib/examples/gb/irq/Makefile29-----------------------------
Dgbdk-lib/examples/gb/irq/irq.c63---------------------------------------------------------------
Mgbdk-lib/include/sms/hardware.h4++++
Mgbdk-lib/libc/targets/z80/gg/Makefile2+-
Mgbdk-lib/libc/targets/z80/sms/Makefile2+-
Mgbdk-lib/libc/targets/z80/sms_int.s35+++++++++++++++--------------------
Agbdk-lib/libc/targets/z80/timer.s82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
10 files changed, 312 insertions(+), 114 deletions(-)

diff --git a/gbdk-lib/examples/cross-platform/irq/Makefile b/gbdk-lib/examples/cross-platform/irq/Makefile @@ -0,0 +1,86 @@ +# If you move this project you can change the directory +# to match your GBDK root directory (ex: GBDK_HOME = "C:/GBDK/" +ifndef GBDK_HOME + GBDK_HOME = ../../../ +endif + +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=gb sms + +# 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_nes = + +LCCFLAGS += $(LCCFLAGS_$(EXT)) # This adds the current platform specific LCC Flags + +LCCFLAGS += -Wl-j -Wm-yS -Wm-yoA -Wm-ya4 -autobank -Wb-ext=.rel -Wb-v # MBC + Autobanking related flags + +# GBDK_DEBUG = ON +ifdef GBDK_DEBUG + LCCFLAGS += -debug -v +endif + + +# You can set the name of the ROM file here +PROJECTNAME = IRQ + +# 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) $(LCCFLAGS) $(CFLAGS) -c -o $@ $< + +# Compile .c files in "res/" to .o object files +$(OBJDIR)/%.o: $(RESDIR)/%.c + $(LCC) $(LCCFLAGS) $(CFLAGS) -c -o $@ $< + +# Compile .s assembly files in "src/" to .o object files +$(OBJDIR)/%.o: $(SRCDIR)/%.s + $(LCC) $(LCCFLAGS) $(CFLAGS) -c -o $@ $< + +# If needed, compile .c files in "src/" to .s assembly files +# (not required if .c is compiled directly to .o) +$(OBJDIR)/%.s: $(SRCDIR)/%.c + $(LCC) $(LCCFLAGS) $(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/irq/Makefile.targets b/gbdk-lib/examples/cross-platform/irq/Makefile.targets @@ -0,0 +1,54 @@ + +# 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=sm83 PLAT=gb EXT=gb + + +gbc-clean: + ${MAKE} clean-target EXT=gbc +gbc: + ${MAKE} build-target PORT=sm83 PLAT=gb EXT=gbc + + +pocket-clean: + ${MAKE} clean-target EXT=pocket +pocket: + ${MAKE} build-target PORT=sm83 PLAT=ap EXT=pocket + + +megaduck-clean: + ${MAKE} clean-target EXT=duck +megaduck: + ${MAKE} build-target PORT=sm83 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 + +nes-clean: + ${MAKE} clean-target EXT=nes +nes: + ${MAKE} build-target PORT=mos6502 PLAT=nes EXT=nes + diff --git a/gbdk-lib/examples/cross-platform/irq/src/irq.c b/gbdk-lib/examples/cross-platform/irq/src/irq.c @@ -0,0 +1,68 @@ +#include <gbdk/platform.h> +#include <gbdk/console.h> + +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +// counters are 16-bit so we need a mutual exclusion access +unsigned int vbl_cnt, tim_cnt; + +void vbl(void) +{ + // Upon IRQ, interrupts are automatically disabled + vbl_cnt++; +} + +void tim(void) +{ + // Upon IRQ, interrupts are automatically disabled + tim_cnt++; +} + +void print_counter(void) +{ + unsigned int cnt; + + // Ensure mutual exclusion + CRITICAL { + cnt = tim_cnt; + } + + printf(" TIM %u", cnt); + gotoxy(9, posy()); + + // Ensure mutual exclusion + CRITICAL { + cnt = vbl_cnt; + } + + printf("- VBL %u\n", cnt); +} + +void main(void) +{ + // Ensure mutual exclusion + CRITICAL { + vbl_cnt = tim_cnt = 0; + add_VBL(vbl); + add_TIM(tim); + } + +#if defined(NINTENDO) + // Set TMA to divide clock by 0x100 + TMA_REG = 0x00U; + // Set clock to 4096 Hertz + TAC_REG = 0x04U; +#elif defined(SEGA) + TMA_REG = 0xFCU; +#endif + + // Handle VBL and TIM interrupts + set_interrupts(VBL_IFLAG | TIM_IFLAG); + + for(;;) { + print_counter(); + delay(1000UL); + } +} diff --git a/gbdk-lib/examples/gb/irq/Makefile b/gbdk-lib/examples/gb/irq/Makefile @@ -1,29 +0,0 @@ -# If you move this project you can change the directory -# to match your GBDK root directory (ex: GBDK_HOME = "C:/GBDK/" -ifndef GBDK_HOME - GBDK_HOME = ../../../ -endif - -LCC = $(GBDK_HOME)bin/lcc -Wa-l -Wl-m -Wl-j - -BINS = irq.gb - -# GBDK_DEBUG = ON -ifdef GBDK_DEBUG - LCCFLAGS += -debug -v -endif - - -all: $(BINS) - -compile.bat: Makefile - @echo "REM Automatically generated from Makefile" > compile.bat - @make -sn | sed y/\\//\\\\/ | sed s/mkdir\ -p\/mkdir\/ | grep -v make >> compile.bat - -# Compile and link single file in one pass -%.gb: %.c - $(LCC) $(LCCFLAGS) -o $@ $< - -clean: - rm -f *.o *.lst *.map *.gb *~ *.rel *.cdb *.ihx *.lnk *.sym *.asm *.noi *.rst - diff --git a/gbdk-lib/examples/gb/irq/irq.c b/gbdk-lib/examples/gb/irq/irq.c @@ -1,63 +0,0 @@ -#include <gb/gb.h> -#include <gbdk/console.h> - -#include <stdint.h> -#include <stdio.h> -#include <string.h> - -// counters are 16-bit so we need a mutual exclusion access -unsigned int vbl_cnt, tim_cnt; - -void vbl(void) -{ - // Upon IRQ, interrupts are automatically disabled - vbl_cnt++; -} - -void tim(void) -{ - // Upon IRQ, interrupts are automatically disabled - tim_cnt++; -} - -void print_counter(void) -{ - unsigned int cnt; - - // Ensure mutual exclusion - CRITICAL { - cnt = tim_cnt; - } - - printf(" TIM %u", cnt); - gotoxy(9, posy()); - - // Ensure mutual exclusion - CRITICAL { - cnt = vbl_cnt; - } - - printf("- VBL %u\n", cnt); -} - -void main(void) -{ - // Ensure mutual exclusion - CRITICAL { - vbl_cnt = tim_cnt = 0; - add_VBL(vbl); - add_TIM(tim); - } - - // Set TMA to divide clock by 0x100 - TMA_REG = 0x00U; - // Set clock to 4096 Hertz - TAC_REG = 0x04U; - // Handle VBL and TIM interrupts - set_interrupts(VBL_IFLAG | TIM_IFLAG); - - while(1) { - print_counter(); - delay(1000UL); - } -} diff --git a/gbdk-lib/include/sms/hardware.h b/gbdk-lib/include/sms/hardware.h @@ -244,6 +244,10 @@ static volatile UBYTE AT(0xfffd) MAP_FRAME0; static volatile UBYTE AT(0xfffe) MAP_FRAME1; static volatile UBYTE AT(0xffff) MAP_FRAME2; +extern volatile UBYTE TIMA_REG; +extern volatile UBYTE TMA_REG; +extern volatile UBYTE TAC_REG; + extern volatile UBYTE VDP_ATTR_SHIFT; #define VBK_TILES 0 diff --git a/gbdk-lib/libc/targets/z80/gg/Makefile b/gbdk-lib/libc/targets/z80/gg/Makefile @@ -23,7 +23,7 @@ ASSRC = set_interrupts.s \ scroll.s cls.s gotoxy.s \ palette.s set_palette.s \ pad.s pad_ex.s \ - sms_int.s nmi.s \ + sms_int.s nmi.s timer.s \ mode.s clock.s get_r_reg.s \ delay.s \ emu_debug_printf.s \ diff --git a/gbdk-lib/libc/targets/z80/sms/Makefile b/gbdk-lib/libc/targets/z80/sms/Makefile @@ -23,7 +23,7 @@ ASSRC = set_interrupts.s \ scroll.s cls.s gotoxy.s \ palette.s set_palette.s \ pad.s pad_ex.s \ - sms_int.s nmi.s \ + sms_int.s nmi.s timer.s \ mode.s clock.s get_r_reg.s \ delay.s \ emu_debug_printf.s \ diff --git a/gbdk-lib/libc/targets/z80/sms_int.s b/gbdk-lib/libc/targets/z80/sms_int.s @@ -70,24 +70,18 @@ _INT_ISR:: ld (.vbl_done), a ;; call user-defined VBlank handlers - ld hl, (.VBLANK_HANDLER0) - ld a, h - or l - jp z, 3$ - CALL_HL - - ld hl, (.VBLANK_HANDLER1) - ld a, h - or l - jp z, 3$ - CALL_HL - - ld hl, (.VBLANK_HANDLER2) - ld a, h - or l - jp z, 3$ - CALL_HL - jp 3$ + .irp idx,.VBLANK_HANDLER0,.VBLANK_HANDLER1,.VBLANK_HANDLER2 + ld hl, (idx) + ld a, h + or l + jp z, 5$ + CALL_HL + .endm +5$: + ld hl, #3$ + push hl + ld hl, (.TIM_DISPATCHER) + jp (hl) 2$: ;; handle HBlank @@ -183,10 +177,8 @@ _remove_VBL:: jr nz, 2$ ret -_remove_TIM:: _remove_SIO:: _remove_JOY:: -_add_TIM:: _add_SIO:: _add_JOY:: .empty_function: @@ -194,6 +186,8 @@ _add_JOY:: .area _INITIALIZED +.TIM_DISPATCHER:: + .ds 0x02 .HBLANK_HANDLER0: .ds 0x02 .VBLANK_HANDLER0: @@ -207,6 +201,7 @@ _add_JOY:: .area _INITIALIZER .dw .empty_function + .dw .empty_function .dw 0x0000 .dw 0x0000 .dw 0x0000 diff --git a/gbdk-lib/libc/targets/z80/timer.s b/gbdk-lib/libc/targets/z80/timer.s @@ -0,0 +1,81 @@ + .include "global.s" + + .title "Timer dispatcher" + .module TIMDispatcher + + .globl .add_int, .remove_int + .globl .TIM_DISPATCHER + + .area _HOME + +LowPri_TIM_Dispatcher: + ld hl, #_TIMA_REG + inc (hl) + ret nz + ei + jp .TIM_continue +TIM_Dispatcher: + ld hl, #_TIMA_REG + inc (hl) + ret nz +.TIM_continue: + ld a, (_TMA_REG) + ld (hl), a + + .irp idx,.TIM_HANDLER0,.TIM_HANDLER1,.TIM_HANDLER2 + ld hl, (idx) + ld a, h + or l + jp z, 1$ + CALL_HL + .endm +1$: + ret + +_remove_TIM:: + ld b, h + ld c, l + ld hl, #.TIM_HANDLER0 + jp .remove_int + +_add_low_priority_TIM:: + ld b, h + ld c, l + ld hl, #LowPri_TIM_Dispatcher + jr .add_TIM +_add_TIM:: + ld b, h + ld c, l + ld hl, #TIM_Dispatcher +.add_TIM: + ld (.TIM_DISPATCHER), hl + ld hl, #.TIM_HANDLER0 + jp .add_int + + .area _DATA + +_TAC_REG:: + .ds 0x01 + + .area _INITIALIZED + +_TIMA_REG:: + .ds 0x01 +_TMA_REG:: + .ds 0x01 +.TIM_HANDLER0: + .ds 0x02 +.TIM_HANDLER1: + .ds 0x02 +.TIM_HANDLER2: + .ds 0x02 + .ds 0x02 + + .area _INITIALIZER + + .db 0xff + .db 0xff + .dw 0x0000 + .dw 0x0000 + .dw 0x0000 + .dw 0x0000 +

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