gbdk-2020 | GameBoy Development Kit |
| download: https://git.y1.nz/archives/gbdk.tar.gz | |
| README | Files | Log | Refs | LICENSE |
commit b0c35d6b352378dd7ac7dd6126671ef9bb6c3d34 parent f4f2cecf2c2d2ce561453de02a1f7589862c4bbc Author: bbbbbr <bbbbbr@users.noreply.github.com> Date: Thu, 16 Oct 2025 02:29:45 -0700 Examples: gb-rand: minor improvements (#823) - fast modulo alternative - triangle and bell curve distributions per discord chat - modernized makefile Diffstat:
| M | gbdk-lib/examples/gb/rand/Makefile | 101 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- |
| A | gbdk-lib/examples/gb/rand/Makefile.targets | 54 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| D | gbdk-lib/examples/gb/rand/rand.c | 58 | ---------------------------------------------------------- |
| A | gbdk-lib/examples/gb/rand/src/rand.c | 109 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
4 files changed, 256 insertions(+), 66 deletions(-)
diff --git a/gbdk-lib/examples/gb/rand/Makefile b/gbdk-lib/examples/gb/rand/Makefile @@ -1,17 +1,102 @@ -CC = ../../../bin/lcc -Wa-l -Wl-m -Wl-j +# 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 -BINS = rand.gb +LCC = $(GBDK_HOME)/bin/lcc -all: $(BINS) +# 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 # gb pocket megaduck sms gg nes + +# Configure platform specific LCC flags here: +LCCFLAGS_gb = +LCCFLAGS_pocket = +LCCFLAGS_duck = +LCCFLAGS_gbc = +LCCFLAGS_sms = +LCCFLAGS_gg = +LCCFLAGS_nes = + +LCCFLAGS += $(LCCFLAGS_$(EXT)) # This adds the current platform specific LCC Flags + +LCCFLAGS += -Wl-j +LCCFLAGS += -Wf-MMD -Wf-Wp-MP # Header file dependency output (-MMD) for Makefile use + per-header Phony rules (-MP) +CFLAGS += -Wf-MMD -Wf-Wp-MP # Header file dependency output (-MMD) for Makefile use + per-header Phony rules (-MP) + +# GBDK_DEBUG = ON +ifdef GBDK_DEBUG + LCCFLAGS += -debug -v +endif + +# You can set the name of the ROM file here +PROJECTNAME = rand_plot + + +# 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) + +# Dependencies (using output from -Wf-MMD -Wf-Wp-MP) +DEPS = $(OBJS:%.o=%.d) + +-include $(DEPS) + +# Builds all targets sequentially +all: $(TARGETS) compile.bat: Makefile @echo "REM Automatically generated from Makefile" > compile.bat - @make -sn | sed y/\\//\\\\/ | grep -v make >> compile.bat + @make -sn | sed y/\\//\\\\/ | sed s/mkdir\ -p\/mkdir\/ | grep -v make >> compile.bat + +test: + echo $(CSOURCES) + + +# Compile .c files in "src/" to .o object files +$(OBJDIR)/%.o: $(SRCDIR)/%.c + $(LCC) $(CFLAGS) -c -o $@ $< -# Compile and link single file in one pass -%.gb: %.c - $(CC) -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 in "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: - rm -f *.o *.lst *.map *.gb *~ *.rel *.cdb *.ihx *.lnk *.sym *.asm *.noi + @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/gb/rand/Makefile.targets b/gbdk-lib/examples/gb/rand/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/gb/rand/rand.c b/gbdk-lib/examples/gb/rand/rand.c @@ -1,58 +0,0 @@ -/*************************************************************************** - * * - * Module : rand.c * - * * - * Purpose : A test for the rand() function, for the GBDK * - * * - * Version : 1, Januari 6 1998 * - * * - * Author : Luc Van den Borre ( Homepage : NOC.BASE.ORG ) * - * * - **************************************************************************/ - -#include <gb/gb.h> -#include <rand.h> -#include <gb/drawing.h> -#include <stdio.h> -#include <string.h> - -UBYTE accu[80]; -UBYTE accua[80]; - -void main(void) -{ - UBYTE r, s, t = 0, u = 0; - UWORD seed; - - memset(accu, 0, sizeof(accu)); - memset(accua, 0, sizeof(accua)); - - /* We use the DIV register to get a random initial seed */ - puts("Getting seed"); - puts("Push any key (1)"); - waitpad(0xFF); - waitpadup(); - seed = DIV_REG; - puts("Push any key (2)"); - waitpad(0xFF); - waitpadup(); - seed |= (UWORD)DIV_REG << 8; - - /* initarand() calls initrand() */ - initarand(seed); - - do { - r = rand(); - s = arand(); - - if(r < 80) { - t = ++accu[r]; - plot(r, 144-t, LTGREY, SOLID); - } - if(s < 80) { - u = ++accua[s]; - plot(s+80, 144-u, DKGREY, SOLID); - } - } - while(t != 144 && u != 144); -} diff --git a/gbdk-lib/examples/gb/rand/src/rand.c b/gbdk-lib/examples/gb/rand/src/rand.c @@ -0,0 +1,109 @@ +/*************************************************************************** + * * + * Module : rand.c * + * * + * Purpose : A test for the rand() function, for the GBDK * + * * + * Version : 1, Januari 6 1998 * + * * + * Author : Luc Van den Borre ( Homepage : NOC.BASE.ORG ) * + * * + **************************************************************************/ + +#include <gb/gb.h> +#include <rand.h> +#include <gb/drawing.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#define RANGE_SIZE (160u / 4u) +#define HALF_RANGE_SIZE (RANGE_SIZE / 2u) + +UBYTE accu[RANGE_SIZE]; +UBYTE accua[RANGE_SIZE]; +UBYTE accut[RANGE_SIZE]; +UBYTE accub[RANGE_SIZE]; + +// Fast alternative to modulo for arbitrary 8 bit range sizes +// (range sizes that are exact powers of 2 can use faster bit shift or mask reductions) +// +// see: https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ +// +// Max value for RANGE is 256 +#define RAND_RANGE_8BIT(randval, range) (uint8_t)(((randval & 0xFFu) * range) >> 8) + +void main(void) +{ + uint16_t seed; + + memset(accu, 0, sizeof(accu)); + memset(accua, 0, sizeof(accua)); + memset(accut, 0, sizeof(accut)); + memset(accut, 0, sizeof(accub)); + + /* We use the DIV register to get a random initial seed */ + puts("Getting seed"); + puts("Push any key (1)"); + waitpad(0xFF); + waitpadup(); + seed = DIV_REG; + puts("Push any key (2)"); + waitpad(0xFF); + waitpadup(); + seed |= (UWORD)DIV_REG << 8; + + // initarand() calls initrand() + initarand(seed); + + // Draw some divider lines + line(RANGE_SIZE * 1, 0, RANGE_SIZE * 1, 143); + line(RANGE_SIZE * 2, 0, RANGE_SIZE * 2, 143); + line(RANGE_SIZE * 3, 0, RANGE_SIZE * 3, 143); + + while (1) { + + // Generate standard random values in the range of 0 .. RANGE_SIZE - 1 + // and accumulate the values into buckets, then plot the bucket sizes + + // Using rand() + uint8_t r = RAND_RANGE_8BIT(rand(), RANGE_SIZE); + + // Using arand() + uint8_t ra = RAND_RANGE_8BIT(arand(), RANGE_SIZE); + + // Create a triangle distribution using (rand - rand) + uint8_t rt1 = RAND_RANGE_8BIT(rand(), HALF_RANGE_SIZE); + uint8_t rt2 = RAND_RANGE_8BIT(rand(), HALF_RANGE_SIZE); + uint8_t rt = HALF_RANGE_SIZE + (rt1 - rt2); + + // Create a bell-curve-ish distribution using (rand - rand) + (rand - rand) + uint8_t rb1 = RAND_RANGE_8BIT(rand(), HALF_RANGE_SIZE / 2); + uint8_t rb2 = RAND_RANGE_8BIT(rand(), HALF_RANGE_SIZE / 2); + uint8_t rb3 = RAND_RANGE_8BIT(rand(), HALF_RANGE_SIZE / 2); + uint8_t rb4 = RAND_RANGE_8BIT(rand(), HALF_RANGE_SIZE / 2); + uint8_t rb = HALF_RANGE_SIZE + (rb1 - rb2) + (rb3 - rb4); + + + // Plot the updated rand value buckets + // + // rand | arand | rand with triangle distribution | bell-curve-ish + + uint8_t r_bucket_height = ++accu[r]; + if (r_bucket_height > 144) break; + plot(r + (RANGE_SIZE * 0), 144-r_bucket_height, LTGREY, SOLID); + + uint8_t ra_bucket_height = ++accua[ra]; + if (ra_bucket_height > 144) break; + plot(ra + (RANGE_SIZE * 1), 144 - ra_bucket_height, DKGREY, SOLID); + + uint8_t rt_bucket_height = ++accut[rt]; + if (rt_bucket_height > 144) break; + plot(rt + (RANGE_SIZE * 2), 144 - rt_bucket_height, BLACK, SOLID); + + uint8_t rb_bucket_height = ++accub[rb]; + if (rb_bucket_height > 144) break; + plot(rb + (RANGE_SIZE * 3), 144 - rb_bucket_height, BLACK, SOLID); + } +} +
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.