Merge pull request #36 from risingPhil/feature/load-without-multiboot

Proof Of Concept: Load PokeTransporterGB WITHOUT multiboot
This commit is contained in:
The Gears of Progress 2025-04-06 17:10:41 -04:00 committed by GitHub
commit 1a68b30c8b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 340 additions and 1 deletions

View File

@ -139,10 +139,14 @@ export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
@mkdir -p loader/data
@cp $(TARGET).gba loader/data/multiboot_rom.bin
@$(MAKE) -C loader
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@$(MAKE) -C loader clean
@rm -fr $(BUILD) $(TARGET).elf $(TARGET).gba

View File

@ -13,9 +13,10 @@ Currently the only release is in English. Releases supporting other languages is
Currently English versions of Red, Blue, Yellow, Gold, Silver, Crystal are supported- plus English, Spanish, German, Italian, French versions of Ruby, Sapphire, FireRed, LeafGreen, and Emerald. Compatibility for other languages is currently in development and will be added in the near future.
## Usage
Poké Transporter GB is a Multiboot program for the Game Boy Advance. There are two main ways to run the Poké Transporter GB ROM on a Game Boy Advance:
Poké Transporter GB is a Multiboot program for the Game Boy Advance. There are 3 main ways to run the Poké Transporter GB ROM on a Game Boy Advance:
- Use a program such as FIX94's [GBA Link Cable ROM Sender](https://github.com/FIX94/gba-link-cable-rom-sender) on a GameCube or Wii running Homebrew along with a GBA GameCube Link Cable
- Upload the Multiboot ROM to a GBA Flash Cart, launch the game in Multiboot mode (often by holding L when selecting the ROM), and swap the Game Pak after the program loads.
- Copy the loader.gba file to a GBA Flash Cart and swap the Game Pak after the program loads. This is useful for flashcarts that don't support launching multiboot roms directly. (SuperCard SD for example)
Please note that transfering Pokémon will only work with a Game Boy Color Link Cable. Game Boy Advance Link Cables will not work.

27
docker-compose.yml Normal file
View File

@ -0,0 +1,27 @@
# This docker-compose file allows you to pull the devkitpro/devkitarm docker container
# and use it to build the Poke Transporter GB rom(s).
#
# To launch the container itself in the background:
# docker compose up -d
# Note the container name being printed in the terminal. In my case it was this: poke_transporter_gb-build-1
#
# Then get a terminal into the container like this:
# docker exec -it poke_transporter_gb-build-1 /bin/bash
#
# Now you can build the project inside this terminal.
version: "3.5"
services:
build:
image: devkitpro/devkitarm
working_dir: /usr/Poke_Transporter_GB
command: tail -F anything
volumes:
- type: bind
source: ${SSH_AUTH_SOCK}
target: ${SSH_AUTH_SOCK}
- type: bind
source: ${PWD}
target: /usr/Poke_Transporter_GB

188
loader/Makefile Normal file
View File

@ -0,0 +1,188 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/gba_rules
#---------------------------------------------------------------------------------
# the LIBGBA path is defined in gba_rules, but we have to define LIBTONC ourselves
#---------------------------------------------------------------------------------
LIBTONC := $(DEVKITPRO)/libtonc
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files
# DATA is a list of directories containing binary data
# GRAPHICS is a list of directories containing files to be processed by grit
#
# All directories are specified relative to the project directory where
# the makefile is found
#
#---------------------------------------------------------------------------------
TARGET := $(notdir $(CURDIR))
BUILD := build
SOURCES := source
INCLUDES := include
DATA := data
MUSIC :=
GRAPHICS := graphics
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -mthumb -mthumb-interwork
CFLAGS := -g -Wall -O2\
-mcpu=arm7tdmi -mtune=arm7tdmi\
$(ARCH)
CFLAGS += $(INCLUDE)
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := -g $(ARCH)
LDFLAGS = -g $(ARCH) -Wl,-Map,$(notdir $*.map)
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
#---------------------------------------------------------------------------------
LIBS := -lmm -ltonc
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib.
# the LIBGBA path should remain in this list if you want to use maxmod
#---------------------------------------------------------------------------------
LIBDIRS := $(LIBGBA) $(LIBTONC)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir)) \
$(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
PNGFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.png)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
ifneq ($(strip $(MUSIC)),)
export AUDIOFILES := $(foreach dir,$(notdir $(wildcard $(MUSIC)/*.*)),$(CURDIR)/$(MUSIC)/$(dir))
BINFILES += soundbank.bin
endif
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
export OFILES_SOURCES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export OFILES_GRAPHICS := $(PNGFILES:.png=.o)
export OFILES := $(OFILES_BIN) $(OFILES_SOURCES) $(OFILES_GRAPHICS)
export HFILES := $(addsuffix .h,$(subst .,_,$(BINFILES))) $(PNGFILES:.png=.h)
export INCLUDE := $(foreach dir,$(INCLUDES),-iquote $(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean
#---------------------------------------------------------------------------------
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -f data/*
@rm -fr $(BUILD) $(TARGET).elf $(TARGET).gba
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT).gba : $(OUTPUT).elf
$(OUTPUT).elf : $(OFILES)
$(OFILES_SOURCES) : $(HFILES)
#---------------------------------------------------------------------------------
# The bin2o rule should be copied and modified
# for each extension used in the data directories
#---------------------------------------------------------------------------------
#---------------------------------------------------------------------------------
# rule to build soundbank from music files
#---------------------------------------------------------------------------------
soundbank.bin soundbank.h : $(AUDIOFILES)
#---------------------------------------------------------------------------------
@mmutil $^ -osoundbank.bin -hsoundbank.h
#---------------------------------------------------------------------------------
# This rule links in binary data with the .bin extension
#---------------------------------------------------------------------------------
%.bin.o %_bin.h : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
#---------------------------------------------------------------------------------
# This rule creates assembly source files using grit
# grit takes an image file and a .grit describing how the file is to be processed
# add additional rules like this for each image extension
# you use in the graphics folders
#---------------------------------------------------------------------------------
%.s %.h: %.png %.grit
#---------------------------------------------------------------------------------
@echo "grit $(notdir $<)"
@grit $< -fts -o$*
# make likes to delete intermediate files. This prevents it from deleting the
# files generated by grit after building the GBA ROM.
.SECONDARY:
-include $(DEPSDIR)/*.d
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

7
loader/README.md Normal file
View File

@ -0,0 +1,7 @@
This folder contains a Proof of Concept to load PokeTransporter GB WITHOUT doing the whole multiboot ritual.
It works by embedding the multiboot rom that is generated from the main project build into a separate "normal" gba rom.
And this loader rom will just copy the multiboot rom to EWRAM and jump to the right entrypoint to launch it.
This allows the user to simply launch the loader from a simple flashcart, such as a supercard SD.
After PokeTransporter GB is loaded, the user should be able to swap out the flashcart and insert the Pokémon cartridge.

View File

@ -0,0 +1 @@
../../graphics/ptgb_logo_l.grit

View File

@ -0,0 +1 @@
../../graphics/ptgb_logo_l.png

View File

@ -0,0 +1 @@
../../graphics/ptgb_logo_r.grit

View File

@ -0,0 +1 @@
../../graphics/ptgb_logo_r.png

108
loader/source/main.c Normal file
View File

@ -0,0 +1,108 @@
#include <tonc.h>
#include <string.h>
// This file is autogenerated from the file in the graphics folder
#include "ptgb_logo_l.h"
#include "ptgb_logo_r.h"
#include "multiboot_rom_bin.h"
#define SPRITE_CHAR_BLOCK 4
#define DST_EWRAM (void*)0x02000000
#define MULTIBOOT_ENTRY_POINT (void*)0x020000C0
/**
* An enum with an entry for every separate sprite we load in.
* We use this to ensure a valid index for each sprite
*/
enum SpriteTypes
{
SPRITE_LOGO_L,
SPRITE_LOGO_R
};
/**
* Similarly, the PaletteTypes enum has an entry for every separate palette we're using here.
*/
enum PaletteTypes
{
PAL_LOGO
};
OBJ_ATTR obj_buffer[128];
OBJ_ATTR* logoL = &obj_buffer[SPRITE_LOGO_L];
OBJ_ATTR* logoR = &obj_buffer[SPRITE_LOGO_R];
/**
* Taken from sprite_data.cpp
*/
static void loadSprite(OBJ_ATTR *sprite, const unsigned int objTiles[], int objTilesLen,
u32* tile_id, u32 pal_bank, int attr0, int attr1, u32 priority)
{
memcpy32(&tile_mem[SPRITE_CHAR_BLOCK][*tile_id], objTiles, objTilesLen);
obj_set_attr(sprite, attr0, attr1, ATTR2_PALBANK(pal_bank) | *tile_id | ATTR2_PRIO(priority));
*tile_id += objTilesLen / 32;
obj_hide(sprite);
};
/**
* This function exists to simply load and position the Poke Transporter GB logo
*/
static void load_logo(u32* curSpriteIndex)
{
// load palette
memcpy32(pal_obj_mem + (PAL_LOGO * 16), ptgb_logo_lPal, ptgb_logo_lPalLen);
// now load the tiles of the logo
loadSprite(logoL, ptgb_logo_lTiles, ptgb_logo_lTilesLen, curSpriteIndex, PAL_LOGO, ATTR0_SQUARE, ATTR1_SIZE_64x64, 1);
loadSprite(logoR, ptgb_logo_rTiles, ptgb_logo_rTilesLen, curSpriteIndex, PAL_LOGO, ATTR0_SQUARE, ATTR1_SIZE_64x64, 1);
// Set position
obj_set_pos(logoL, 56, 12);
obj_set_pos(logoR, 56 + 64, 12);
obj_unhide_multi(logoL, 1, 2);
oam_copy(oam_mem, obj_buffer, 2); // Update first OAM object
}
/**
* Loads the PokeTransporter multiboot rom into EWRAM
*/
static void load_multiboot_rom(const void *src, size_t size)
{
REG_IME = 0; // Disable all interrupts
memcpy(DST_EWRAM, src, size);
REG_IME = 1;
}
/**
* Now jump to the multiboot rom address and start execution
*/
static void execute_multiboot()
{
// Function pointer to EWRAM execution entry
void (*entry)(void) = MULTIBOOT_ENTRY_POINT;
entry(); // Jump to loaded ROM
}
int main(void)
{
u32 curSpriteIndex = 0;
irq_init(NULL);
irq_enable(II_VBLANK);
tte_init_chr4c_default(0, BG_CBB(0) | BG_SBB(31));
tte_set_pos(92, 68);
tte_write("Loading...");
oam_init(obj_buffer, 128);
load_logo(&curSpriteIndex);
REG_DISPCNT = DCNT_MODE0 | DCNT_BG0 | DCNT_OBJ | DCNT_OBJ_1D;
VBlankIntrWait();
load_multiboot_rom(multiboot_rom_bin, multiboot_rom_bin_size);
execute_multiboot();
}