Create PSP and PS2 ports, switch to gpsp renderer, optimise audio (#235)

- Update software renderer to the gpsp renderer (fast enough to render on slow hardware)
- Convert audio emulation to fixed point (since float is slower on these systems)
- Add PSP as a target for SDL
- Add PS2 as its own target, though it's still using software rendering

Thanks to @kikugrave for adding the initial psp boilerplate and inspiring me to finally finish the ps2 port!
This commit is contained in:
Oliver Bell authored and GitHub committed 2026-03-04 02:10:03 +00:00
1 parent 320f536014
commit 59706b53c1
31 files changed
+6332 -3348

No files matched your search

+1 -1
View File
@@ -5,7 +5,7 @@ ARG VARIANT
FROM mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT}
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y install --no-install-recommends binutils-arm-none-eabi gcc-arm-none-eabi libpng-dev build-essential clang-format-13 xorg-dev libsdl2-dev gcc-mingw-w64 libarchive-tools
&& apt-get -y install --no-install-recommends binutils-arm-none-eabi gcc-arm-none-eabi libpng-dev build-essential clang-format-13 xorg-dev libsdl2-dev g++-mingw-w64 gcc-mingw-w64 libarchive-tools
WORKDIR /deps
RUN git clone https://github.com/pret/agbcc.git && cd agbcc && ./build.sh
+65 -39
View File
@@ -2,39 +2,39 @@ name: CI
on:
push:
branches: [ main ]
branches: [main]
pull_request:
pull_request_target:
jobs:
format:
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}}
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}}
runs-on: ubuntu-22.04
steps:
- name: Checkout PR
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}}
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}}
uses: actions/checkout@master
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Checkout
if: ${{ github.event_name == 'push' }}
uses: actions/checkout@master
- name: Install tools
run: |
sudo apt update && sudo apt install clang-format-13
- name: Check formatting
run: |
make check_format
build-gba:
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}}
runs-on: ubuntu-22.04
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}}
runs-on: ubuntu-24.04
name: Build GBA (USA)
steps:
- name: Checkout PR
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}}
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}}
uses: actions/checkout@master
with:
ref: ${{ github.event.pull_request.head.sha }}
@@ -42,7 +42,7 @@ jobs:
- name: Checkout
if: ${{ github.event_name == 'push' }}
uses: actions/checkout@master
- name: Checkout gh-pages
if: ${{ github.event_name == 'push' }}
uses: actions/checkout@master
@@ -58,7 +58,7 @@ jobs:
- name: Install tools
run: |
sudo apt update && sudo apt install gcc-arm-none-eabi binutils-arm-none-eabi
sudo apt update && sudo apt install gcc-arm-none-eabi binutils-arm-none-eabi libpng-dev
python3 -m pip install gitpython
- name: Install agbcc
@@ -120,17 +120,18 @@ jobs:
cwd: "./gh-pages"
add: "reports maps"
message: ${{ env.REPORTS_COMMIT_MSG }}
build-gba-variants:
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}}
runs-on: ubuntu-22.04
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}}
runs-on: ubuntu-24.04
name: Build GBA (${{ matrix.variant }})
strategy:
matrix:
fail-fast: false
matrix:
variant: ["europe", "japan", "japan_vc", "usa_beta"]
steps:
- name: Checkout PR
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}}
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}}
uses: actions/checkout@master
with:
ref: ${{ github.event.pull_request.head.sha }}
@@ -138,7 +139,7 @@ jobs:
- name: Checkout
if: ${{ github.event_name == 'push' }}
uses: actions/checkout@master
- name: Checkout gh-pages
if: ${{ github.event_name == 'push' }}
uses: actions/checkout@master
@@ -154,7 +155,7 @@ jobs:
- name: Install tools
run: |
sudo apt update && sudo apt install binutils-arm-none-eabi gcc-arm-none-eabi
sudo apt update && sudo apt install binutils-arm-none-eabi gcc-arm-none-eabi libpng-dev
- name: Install agbcc
run: |
@@ -167,15 +168,16 @@ jobs:
ports:
strategy:
matrix:
platform: ["sdl", "sdl_win32", "win32"]
os: ["ubuntu-22.04", "macos-15"]
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}}
fail-fast: false
matrix:
platform: ["sdl", "sdl_win32", "sdl_psp", "win32", "ps2"]
os: ["ubuntu-24.04", "macos-15"]
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}}
runs-on: ${{ matrix.os }}
name: Build ${{ matrix.platform }} (${{ matrix.os }})
steps:
- name: Checkout PR
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}}
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}}
uses: actions/checkout@master
with:
ref: ${{ github.event.pull_request.head.sha }}
@@ -185,34 +187,58 @@ jobs:
uses: actions/checkout@master
- name: Install tools (Linux)
if: ${{ matrix.os == 'ubuntu-22.04' }}
if: ${{ matrix.os == 'ubuntu-24.04' }}
run: |
sudo apt update && sudo apt install xorg-dev libsdl2-dev gcc-mingw-w64 libarchive-tools
sudo apt update && sudo apt install xorg-dev libpng-dev libsdl2-dev g++-mingw-w64 gcc-mingw-w64 libarchive-tools mkisofs
- name: Install Tools (Macos)
if: ${{ matrix.os == 'macos-15' }}
run: |
brew install libpng sdl2 mingw-w64 arm-none-eabi-gcc
brew install libpng sdl2 mingw-w64 arm-none-eabi-gcc cdrtools
- name: Install SDL for win32
if: ${{ matrix.platform == 'sdl_win32' }}
run: |
make SDL2.dll
# TODO: Don't install latest SDK, use a stable version
- name: Install PS2DEV
if: ${{ matrix.platform == 'ps2' }}
run: |
PS2DEV="$HOME/ps2dev"
echo "PS2DEV=$HOME/ps2dev" >> "$GITHUB_ENV"
mkdir -p $PS2DEV
echo "PS2SDK=$PS2DEV/ps2sdk" >> "$GITHUB_ENV"
echo "GSKIT=$PS2DEV/gsKit" >> "$GITHUB_ENV"
echo "$PS2DEV/bin" >> "$GITHUB_PATH"
echo "$PS2DEV/ee/bin" >> "$GITHUB_PATH"
curl -o ps2dev-latest.tar.gz -LC - https://github.com/ps2dev/ps2dev/releases/download/latest/ps2dev-$(if [[ "$OSTYPE" == "darwin"* ]]; then echo macos; else echo ubuntu; fi)-latest.tar.gz
tar -xf ps2dev-latest.tar.gz --strip-components 1 -C $PS2DEV
- name: Install PSPDEV
if: ${{ matrix.platform == 'sdl_psp' }}
run: |
PSPDEV="$HOME/pspdev"
echo "PSPDEV=$HOME/pspdev" >> "$GITHUB_ENV"
mkdir -p $PSPDEV
echo "$PSPDEV/bin" >> "$GITHUB_PATH"
curl -o pspdev-latest.tar.gz -LC - https://github.com/pspdev/pspdev/releases/download/v20260301/pspdev-$(if [[ "$OSTYPE" == "darwin"* ]]; then echo "macos-latest-arm64"; else echo "ubuntu-latest-x86_64"; fi).tar.gz
tar -xf pspdev-latest.tar.gz --strip-components 1 -C $PSPDEV
- name: ${{ matrix.platform }}
run: |
make -j${nproc} ${{ matrix.platform }}
test:
strategy:
matrix:
matrix:
platform: ["sdl"]
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}}
runs-on: ubuntu-22.04
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}}
runs-on: ubuntu-24.04
name: TAS Test ${{ matrix.platform }}
steps:
- name: Checkout PR
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}}
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}}
uses: actions/checkout@master
with:
ref: ${{ github.event.pull_request.head.sha }}
@@ -223,17 +249,17 @@ jobs:
- name: Install tools
run: |
sudo apt update && sudo apt install xorg-dev libsdl2-dev gcc-mingw-w64 libarchive-tools
sudo apt update && sudo apt install xorg-dev libsdl2-dev g++-mingw-w64 gcc-mingw-w64 libarchive-tools
- name: Install SDL for win32
if: ${{ matrix.platform == 'sdl_win32' }}
run: |
make SDL2.dll
- name: Build ${{ matrix.platform }}
run: |
make -j${nproc} ${{ matrix.platform }} TAS_TESTING=1
- name: Run TAS
timeout-minutes: 1
env:
@@ -242,12 +268,12 @@ jobs:
./sa2.${{ matrix.platform }}
level_editor:
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}}
runs-on: ubuntu-22.04
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}}
runs-on: ubuntu-24.04
name: Level editor (BriBaSA)
steps:
- name: Checkout PR
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}}
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}}
uses: actions/checkout@master
with:
ref: ${{ github.event.pull_request.head.sha }}
@@ -259,7 +285,7 @@ jobs:
- name: Install deps
run: |
sudo apt update && sudo apt install xorg-dev libsdl2-dev
- name: Build
run: |
make -j${nproc} bribasa
+6
View File
@@ -85,6 +85,12 @@ libagbsyscall/*.s
*.exe
*.dll
*.sdl
*.iso
# PSP build outputs
EBOOT.PBP
PARAM.SFO
sa2_debug.log
# third party deps
/ext
+28 -6
View File
@@ -12,17 +12,29 @@ Install WSL (Ubuntu). Once installed, open this project in the WSL terminal and
### Install system requirements
#### On Linux (including WSL)
```
```bash
sudo apt update
sudo apt install build-essential binutils-arm-none-eabi gcc-arm-none-eabi libpng-dev xorg-dev libsdl2-dev gcc-mingw-w64 libarchive-tools
```
sudo apt install build-essential binutils-arm-none-eabi gcc-arm-none-eabi libpng-dev xorg-dev libsdl2-dev g++-mingw-w64 gcc-mingw-w64 libarchive-tools
# Optional, if you want to compile for the PS2 you'll need
sudo apt install mkisofs
```
#### On MacOS
```
```bash
brew install libpng sdl2 mingw-w64 arm-none-eabi-gcc
# Optional, if you want to compile for the PS2 you'll need
brew install cdrtools
```
#### PS2DEV and PSPDEV
For compiling for the PSP or PS2, ensure that you install the required SDK
- [PS2DEV](https://github.com/ps2dev/ps2dev)
- [PSPDEV](https://github.com/pspdev/pspdev)
## Building
Clone/Download the repo
@@ -33,9 +45,9 @@ Run all commands in the same folder as this project. All outputs go into the sam
**NOTE**: You can significantly speed up initial build times by passing the number of processes you wish to use for the build. For example `make -j4` with 4 being the number of cores
### PC port
### Ports
The PC port targets different platforms depending on where you are going to be playing it.
The codebase targets different platforms depending on where you are going to be playing it.
#### For Windows
@@ -54,6 +66,16 @@ Tip: On Linux and MacOS this can be opened with `wine sa2.sdl_win32.exe`
1. `sa2.sdl` will be created
1. Launch the game from the terminal with `./sa2.sdl`
#### For PSP
1. Run `make sdl_psp`
1. `EBOOT.PBP` will be created
#### For PS2
1. Run `make ps2`
1. `sa2.ps2.iso` will be created
### GBA rom
1. Clone [agbcc](https://github.com/SAT-R/agbcc) repo into another folder
+112 -24
View File
@@ -52,6 +52,14 @@ else ifeq ($(CPU_ARCH),i386)
TOOLCHAIN := /usr/x86_64-w64-mingw32/
PREFIX := x86_64-w64-mingw32-
endif
# PSP
else ifeq ($(PLATFORM),sdl_psp)
PSPDEV ?= $(HOME)/pspdev
PSPSDK := $(PSPDEV)/psp/sdk
export PATH := $(PSPDEV)/bin:$(PATH)
PREFIX := psp-
else ifeq ($(PLATFORM),ps2)
PREFIX := mips64r5900el-ps2-elf-
else
# Native
ifneq ($(PLATFORM),sdl)
@@ -74,6 +82,7 @@ CC1 := tools/agbcc/bin/agbcc$(EXE)
CC1_OLD := tools/agbcc/bin/old_agbcc$(EXE)
else
CC1 := $(PREFIX)gcc$(EXE)
CXX := $(PREFIX)g++$(EXE)
CC1_OLD := $(CC1)
endif
@@ -120,6 +129,14 @@ else ifeq ($(PLATFORM),sdl)
ROM := $(BUILD_NAME).sdl
ELF := $(ROM).elf
MAP := $(ROM).map
else ifeq ($(PLATFORM),sdl_psp)
ROM := EBOOT.PBP
ELF := $(BUILD_NAME).sdl_psp.elf
MAP := $(BUILD_NAME).sdl_psp.map
else ifeq ($(PLATFORM),ps2)
ROM := $(BUILD_NAME).$(PLATFORM).iso
ELF := $(ROM:.iso=.elf)
MAP := $(ROM:.iso=.map)
else
ROM := $(BUILD_NAME).$(PLATFORM).exe
ELF := $(ROM:.exe=.elf)
@@ -156,16 +173,28 @@ TILESETS_SUBDIR = graphics/tilesets/
ifeq ($(PLATFORM),gba)
C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/*")
else ifeq ($(PLATFORM),sdl)
C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*")
C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/ps2/*")
else ifeq ($(PLATFORM),sdl_psp)
C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/ps2/*")
else ifeq ($(PLATFORM),ps2)
C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/pret_sdl/*")
else ifeq ($(PLATFORM),sdl_win32)
C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*")
C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/ps2/*")
else ifeq ($(PLATFORM),win32)
C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/pret_sdl/*")
C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/pret_sdl/*" -not -path "*/platform/ps2/*")
else
C_SRCS := $(shell find $(C_SUBDIR) -name "*.c")
endif
C_OBJS := $(patsubst $(C_SUBDIR)/%.c,$(C_BUILDDIR)/%.o,$(C_SRCS))
ifeq ($(PLATFORM),gba)
CXX_SRCS := $(shell find $(C_SUBDIR) -name "*.cc" -not -path "*/platform/*")
else
CXX_SRCS := $(shell find $(C_SUBDIR) -name "*.cc")
endif
CXX_OBJS := $(patsubst $(C_SUBDIR)/%.cc,$(C_BUILDDIR)/%.o,$(CXX_SRCS))
# Platform not included as we only need the headers for decomp scratches
C_HEADERS := $(shell find $(INCLUDE_DIRS) -name "*.h" -not -path "*/platform/*")
@@ -189,7 +218,7 @@ MID_OBJS := $(patsubst $(MID_SUBDIR)/%.mid,$(MID_BUILDDIR)/%.o,$(MID_SRCS))
SOUND_ASM_SRCS := $(wildcard $(SOUND_ASM_SUBDIR)/*.s)
SOUND_ASM_OBJS := $(patsubst $(SOUND_ASM_SUBDIR)/%.s,$(SOUND_ASM_BUILDDIR)/%.o,$(SOUND_ASM_SRCS))
OBJS := $(C_OBJS) $(ASM_OBJS) $(C_ASM_OBJS) $(DATA_ASM_OBJS) $(SONG_OBJS) $(MID_OBJS)
OBJS := $(C_OBJS) $(CXX_OBJS) $(ASM_OBJS) $(C_ASM_OBJS) $(DATA_ASM_OBJS) $(SONG_OBJS) $(MID_OBJS)
OBJS_REL := $(patsubst $(OBJ_DIR)/%,%,$(OBJS))
FORMAT_SRC_PATHS := $(shell find . -name "*.c" ! -path '*/src/data/*' ! -path '*/build/*' ! -path '*/ext/*')
@@ -225,6 +254,12 @@ else
ifeq ($(PLATFORM),sdl)
CC1FLAGS += -Wno-parentheses-equality -Wno-unused-value
CPPFLAGS += -D TITLE_BAR=$(BUILD_NAME).$(PLATFORM) -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 $(shell sdl2-config --cflags)
else ifeq ($(PLATFORM),sdl_psp)
CC1FLAGS += -G0
CPPFLAGS += -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 -D SDL_MAIN_HANDLED -I$(PSPDEV)/psp/include/SDL2 -I$(PSPDEV)/psp/include -I$(PSPSDK)/include -D_PSP_FW_VERSION=600
else ifeq ($(PLATFORM),ps2)
CC1FLAGS += -G0 -Wno-parentheses-equality -Wno-unused-value -ffast-math
CPPFLAGS += -D PLATFORM_GBA=0 -D PLATFORM_SDL=0 -D PLATFORM_WIN32=0 -D_EE -D__PS2__ -I$(PS2SDK)/common/include -I$(PS2SDK)/ee/include -I$(PS2DEV)/gsKit/include -I$(PS2SDK)/ports/include
else ifeq ($(PLATFORM),sdl_win32)
CPPFLAGS += -D TITLE_BAR=$(BUILD_NAME).$(PLATFORM) -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 $(SDL_MINGW_FLAGS)
else ifeq ($(PLATFORM),win32)
@@ -241,24 +276,18 @@ else
endif
endif
ifeq ($(PLATFORM),gba)
ASFLAGS += -mcpu=arm7tdmi -mthumb-interwork
CC1FLAGS += -mthumb-interwork
else
ifeq ($(PLATFORM), sdl)
# for modern we are using a modern compiler
# so instead of CPP we can use gcc -E to "preprocess only"
CPP := $(CC1) -E
endif
# Allow file input through stdin on modern GCC and set it to "compile only"
CC1FLAGS += -x c -S
endif
ifeq ($(DEBUG),1)
CC1FLAGS += -g3 -O0
CPPFLAGS += -D DEBUG=1
else
CC1FLAGS += -O2
ifeq ($(PLATFORM),sdl_psp)
# -O3 for PSP (Allegrex MIPS, small D-cache)
CC1FLAGS += -O3 -funroll-loops -fomit-frame-pointer
else ifeq ($(PLATFORM),ps2)
CC1FLAGS += -O3 -fomit-frame-pointer
else
CC1FLAGS += -O2
endif
CPPFLAGS += -D DEBUG=0
endif
@@ -285,6 +314,26 @@ else
CPPFLAGS += -D ENABLE_DECOMP_CREDITS=1
endif
CXXFLAGS := $(CC1FLAGS) $(CPPFLAGS) -fno-rtti -fno-exceptions -std=c++11
ifeq ($(PLATFORM),gba)
ASFLAGS += -mcpu=arm7tdmi -mthumb-interwork
CC1FLAGS += -mthumb-interwork
else
ifeq ($(PLATFORM), sdl)
# for modern we are using a modern compiler
# so instead of CPP we can use gcc -E to "preprocess only"
CPP := $(CC1) -E
else ifeq ($(PLATFORM), sdl_psp)
CPP := $(CC1) -E
else ifeq ($(PLATFORM), ps2)
ASFLAGS += -msingle-float
endif
# Allow file input through stdin on modern gcc/g++ and set it to "compile only"
CC1FLAGS += -x c -S
CXXFLAGS += -x c++ -S
endif
### LINKER FLAGS ###
# GBA
@@ -297,7 +346,7 @@ else ifeq ($(PLATFORM),sdl)
else
MAP_FLAG := -Xlinker -Map=
endif
# Win32
# Win32, PSP, PS2
else
MAP_FLAG := -Xlinker -Map=
endif
@@ -307,6 +356,10 @@ ifeq ($(PLATFORM),gba)
LIBS := $(ROOT_DIR)/tools/agbcc/lib/libgcc.a $(ROOT_DIR)/tools/agbcc/lib/libc.a $(LIBABGSYSCALL_LIBS)
else ifeq ($(PLATFORM),sdl)
LIBS := $(shell sdl2-config --cflags --libs)
else ifeq ($(PLATFORM),sdl_psp)
LIBS := -L$(PSPDEV)/psp/lib -L$(PSPSDK)/lib -lSDL2 -lm -lGL -lpspvram -lpspaudio -lpspvfpu -lpspdisplay -lpspgu -lpspge -lpsphprm -lpspctrl -lpsppower -lpspdebug -lpspnet -lpspnet_apctl -Wl,-zmax-page-size=128
else ifeq ($(PLATFORM),ps2)
LIBS := -T$(PS2SDK)/ee/startup/linkfile -L$(PS2SDK)/common/lib -L$(PS2SDK)/ee/lib -L$(PS2DEV)/gsKit/lib -L$(PS2SDK)/ports/lib -lgskit -ldmakit -lps2_drivers -lmc -lpatches -Wl,-zmax-page-size=128
else ifeq ($(PLATFORM),sdl_win32)
LIBS := -mwin32 -lkernel32 -lwinmm -lmingw32 -lxinput $(SDL_MINGW_LIBS)
else ifeq ($(PLATFORM), win32)
@@ -316,7 +369,7 @@ endif
#### MAIN TARGETS ####
# these commands will run regardless of deps being completed
.PHONY: clean tools tidy clean-tools $(TOOLDIRS) libagbsyscall
.PHONY: clean tools tidy clean-tools $(TOOLDIRS) libagbsyscall ps2
# Ensure required directories exist
$(shell mkdir -p $(C_BUILDDIR) $(ASM_BUILDDIR) $(DATA_ASM_BUILDDIR) $(SOUND_ASM_BUILDDIR) $(SONG_BUILDDIR) $(MID_BUILDDIR))
@@ -397,7 +450,8 @@ clean-tools:
tidy:
$(RM) -r build/*
$(RM) SDL2.dll
$(RM) $(BUILD_NAME)*.exe $(BUILD_NAME)*.elf $(BUILD_NAME)*.map $(BUILD_NAME)*.sdl $(BUILD_NAME)*.gba
$(RM) $(BUILD_NAME)*.exe $(BUILD_NAME)*.elf $(BUILD_NAME)*.map $(BUILD_NAME)*.sdl $(BUILD_NAME)*.gba $(BUILD_NAME)*.iso
$(RM) EBOOT.PBP PARAM.SFO
usa_beta: ; @$(MAKE) GAME_REGION=USA GAME_VARIANT=BETA
@@ -409,6 +463,10 @@ europe: ; @$(MAKE) GAME_REGION=EUROPE
sdl: ; @$(MAKE) PLATFORM=sdl
sdl_psp: ; @$(MAKE) PLATFORM=sdl_psp
ps2: ; @$(MAKE) PLATFORM=ps2
tas_sdl: ; @$(MAKE) sdl TAS_TESTING=1
sdl_win32:
@@ -459,7 +517,7 @@ data/mb_chao_garden_japan.gba.lz: data/mb_chao_garden_japan.gba
%.bin: %.aif ; $(AIF) $< $@
$(ELF): $(OBJS) libagbsyscall
$(ELF): $(OBJS)
ifeq ($(PLATFORM),gba)
@echo "$(LD) -T $(LDSCRIPT) $(MAP_FLAG) $(MAP) <objects> <lib> -o $@"
@$(CPP) -P $(CPPFLAGS) $(LDSCRIPT) > $(OBJ_DIR)/$(LDSCRIPT)
@@ -470,15 +528,34 @@ else
@cd $(OBJ_DIR) && $(CC1) $(MAP_FLAG)$(ROOT_DIR)/$(MAP) $(OBJS_REL) $(LIBS) -o $(ROOT_DIR)/$@
endif
$(ROM): $(ELF)
ifeq ($(PLATFORM),gba)
$(ROM): $(ELF) libagbsyscall
$(OBJCOPY) -O binary --pad-to 0x8400000 $< $@
$(FIX) $@ -p -t"$(TITLE)" -c$(GAME_CODE) -m$(MAKER_CODE) -r$(GAME_REVISION) --silent
else ifeq ($(PLATFORM),sdl)
else ifeq ($(PLATFORM),win32)
$(ROM): $(ELF) libagbsyscall
$(OBJCOPY) -O pei-x86-64 $< $@
else
$(ROM): $(ELF)
ifeq ($(PLATFORM),sdl)
cp $< $@
else ifeq ($(PLATFORM),sdl_psp)
@echo Creating $(ROM) from $(ELF)
@psp-fixup-imports $<
@mksfoex 'Sonic Advance 2' PARAM.SFO
@psp-strip $< -o $(BUILD_NAME).psp_strip.elf
@pack-pbp $@ PARAM.SFO NULL NULL NULL NULL NULL $(BUILD_NAME).psp_strip.elf NULL
@-rm -f $(BUILD_NAME).psp_strip.elf
else ifeq ($(PLATFORM),ps2)
@echo Creating $(ROM) from $(ELF)
@cp -r ps2/ntsc $(OBJ_DIR)/iso
@cp $< $(OBJ_DIR)/iso/$(PS2_GAME_CODE)
@mkisofs -o $(ROM) $(OBJ_DIR)/iso/
else
$(OBJCOPY) -O pei-x86-64 $< $@
endif
endif
# Build c sources, and ensure alignment
$(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.c
@@ -491,11 +568,21 @@ ifeq ($(PLATFORM), gba)
endif
@$(AS) $(ASFLAGS) $(C_BUILDDIR)/$*.s -o $@
$(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.cc
@echo "$(CXX) <flags> -o $@ $<"
@$(shell mkdir -p $(shell dirname '$(C_BUILDDIR)/$*.o'))
@$(CXX) $(CXXFLAGS) -o $(C_BUILDDIR)/$*.s $<
@$(AS) $(ASFLAGS) $(C_BUILDDIR)/$*.s -o $@
# Scan the src dependencies to determine if any dependent files have changed
$(C_BUILDDIR)/%.d: $(C_SUBDIR)/%.c
@$(shell mkdir -p $(shell dirname '$(C_BUILDDIR)/$*.d'))
$(SCANINC) -M $@ $(INCLUDE_SCANINC_ARGS) $<
$(C_BUILDDIR)/%.d: $(C_SUBDIR)/%.cc
@$(shell mkdir -p $(shell dirname '$(C_BUILDDIR)/$*.d'))
$(SCANINC) -M $@ $(INCLUDE_SCANINC_ARGS) $<
# rule for sources from the src dir (parts of libraries)
$(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.s
@echo "$(AS) <flags> -o $@ $<"
@@ -515,6 +602,7 @@ $(DATA_ASM_BUILDDIR)/%.d: $(DATA_ASM_SUBDIR)/%.s
ifneq ($(NODEP),1)
-include $(addprefix $(OBJ_DIR)/,$(C_SRCS:.c=.d))
-include $(addprefix $(OBJ_DIR)/,$(CXX_SRCS:.cc=.d))
-include $(addprefix $(OBJ_DIR)/,$(DATA_ASM_SRCS:.s=.d))
endif
+3 -1
View File
@@ -24,7 +24,9 @@ It builds the following ROMs:
It can also build:
* **sa2.sdl** `make sdl` (Linux/MacOS SDL 64bit port)
* **sa2.sdl_win32.exe** `make sdl_win32` (Windows SDL 64bit port)
* :construction: **sa2.win32.exe** `make win32` (Win32 native port, not functional)
* :construction: **sa2.win32.exe** `make win32` (Win32 OpenGL port, not functional)
* **sa2.ps2.iso** `make ps2` (PlayStation 2 port, requires [PS2DEV](https://github.com/ps2dev/ps2dev))
* **EBOOT.PBP** `make sdl_psp` (PlayStation Portable SDL port, requires [PSPDEV](https://github.com/pspdev/pspdev))
## Current state
+2
View File
@@ -10,6 +10,8 @@
.macro mPtr value
#if defined(__aarch64__) || defined(__x86_64__)
.quad \value
#elif defined(__mips__)
.4byte \value
#else
.int \value
#endif
+1
View File
@@ -63,6 +63,7 @@ MAKER_CODE := 78
BUILD_NAME := sa2
TITLE := SONICADVANC2
GAME_CODE := A2N
PS2_GAME_CODE := SLUS_054.02
# Revision
+3
View File
@@ -42,11 +42,14 @@
#define RENDERER_SOFTWARE 0
#define RENDERER_OPENGL 1
#define RENDERER_COUNT 2
#ifndef RENDERER
#if PLATFORM_WIN32 && !PLATFORM_SDL
// TODO: Only win32 for now
#define RENDERER RENDERER_OPENGL
#else
#define RENDERER RENDERER_SOFTWARE
#endif
#endif
#endif // GUARD_SA2_CONFIG_H
+10
View File
@@ -39,8 +39,18 @@
#define OAM_ENTRY_COUNT 128
#if PORTABLE
// NOTE: Used in gba/types.h, so they have to be defined before the #include
#if defined(__PSP__)
// PSP: Use GBA-native resolution, SDL scales to 480x272
#define DISPLAY_WIDTH 240
#define DISPLAY_HEIGHT 160
#elif defined(__PS2__)
// Runs at 60fps with the "fast draw"
#define DISPLAY_WIDTH 320
#define DISPLAY_HEIGHT 180
#else
#define DISPLAY_WIDTH 426
#define DISPLAY_HEIGHT 240
#endif
// NOTE: We shouldn't consider WIDESCREEN_HACK a permanent thing.
// This hack should best be removed once there's a "native" platform layer.
+151 -130
View File
@@ -5,6 +5,27 @@
#include <stdint.h>
#endif
// these are not hardware registers on ports
// so there is no need to make re-read them
#if PORTABLE
typedef uint8_t reg_u8;
typedef uint16_t reg_u16;
typedef uint32_t reg_u32;
typedef int16_t reg_s16;
typedef int32_t reg_s32;
typedef uint64_t reg_u64;
typedef winreg_t reg_wint;
#else
typedef volatile uint8_t reg_u8;
typedef volatile uint16_t reg_u16;
typedef volatile uint32_t reg_u32;
typedef volatile int16_t reg_s16;
typedef volatile int32_t reg_s32;
typedef volatile uint64_t reg_u64;
typedef volatile winreg_t reg_wint;
#endif
#define IO_SIZE 0x400
#if !PORTABLE
#define REG_BASE 0x4000000 // I/O register base address
@@ -369,155 +390,155 @@ extern unsigned char REG_BASE[IO_SIZE];
// I/O registers
#define REG_DISPCNT (*(vu16 *)REG_ADDR_DISPCNT)
#define REG_DISPSTAT (*(vu16 *)REG_ADDR_DISPSTAT)
#define REG_VCOUNT (*(vu16 *)REG_ADDR_VCOUNT)
#define REG_BG0CNT (*(vu16 *)REG_ADDR_BG0CNT)
#define REG_BG1CNT (*(vu16 *)REG_ADDR_BG1CNT)
#define REG_BG2CNT (*(vu16 *)REG_ADDR_BG2CNT)
#define REG_BG3CNT (*(vu16 *)REG_ADDR_BG3CNT)
#define REG_BG0HOFS (*(vu16 *)REG_ADDR_BG0HOFS)
#define REG_BG0VOFS (*(vu16 *)REG_ADDR_BG0VOFS)
#define REG_BG1HOFS (*(vu16 *)REG_ADDR_BG1HOFS)
#define REG_BG1VOFS (*(vu16 *)REG_ADDR_BG1VOFS)
#define REG_BG2HOFS (*(vu16 *)REG_ADDR_BG2HOFS)
#define REG_BG2VOFS (*(vu16 *)REG_ADDR_BG2VOFS)
#define REG_BG3HOFS (*(vu16 *)REG_ADDR_BG3HOFS)
#define REG_BG3VOFS (*(vu16 *)REG_ADDR_BG3VOFS)
#define REG_BG2PA (*(vu16 *)REG_ADDR_BG2PA)
#define REG_BG2PB (*(vu16 *)REG_ADDR_BG2PB)
#define REG_BG2PC (*(vu16 *)REG_ADDR_BG2PC)
#define REG_BG2PD (*(vu16 *)REG_ADDR_BG2PD)
#define REG_BG2X (*(vu32 *)REG_ADDR_BG2X)
#define REG_BG2X_L (*(vu16 *)REG_ADDR_BG2X_L)
#define REG_BG2X_H (*(vu16 *)REG_ADDR_BG2X_H)
#define REG_BG2Y (*(vu32 *)REG_ADDR_BG2Y)
#define REG_BG2Y_L (*(vu16 *)REG_ADDR_BG2Y_L)
#define REG_BG2Y_H (*(vu16 *)REG_ADDR_BG2Y_H)
#define REG_BG3PA (*(vu16 *)REG_ADDR_BG3PA)
#define REG_BG3PB (*(vu16 *)REG_ADDR_BG3PB)
#define REG_BG3PC (*(vu16 *)REG_ADDR_BG3PC)
#define REG_BG3PD (*(vu16 *)REG_ADDR_BG3PD)
#define REG_BG3X (*(vu32 *)REG_ADDR_BG3X)
#define REG_BG3X_L (*(vu16 *)REG_ADDR_BG3X_L)
#define REG_BG3X_H (*(vu16 *)REG_ADDR_BG3X_H)
#define REG_BG3Y (*(vu32 *)REG_ADDR_BG3Y)
#define REG_BG3Y_L (*(vu16 *)REG_ADDR_BG3Y_L)
#define REG_BG3Y_H (*(vu16 *)REG_ADDR_BG3Y_H)
#define REG_WIN0H (*(volatile winreg_t *)REG_ADDR_WIN0H)
#define REG_WIN1H (*(volatile winreg_t *)REG_ADDR_WIN1H)
#define REG_WIN0V (*(volatile winreg_t *)REG_ADDR_WIN0V)
#define REG_WIN1V (*(volatile winreg_t *)REG_ADDR_WIN1V)
#define REG_WININ (*(volatile winreg_t *)REG_ADDR_WININ)
#define REG_WINOUT (*(volatile winreg_t *)REG_ADDR_WINOUT)
#define REG_MOSAIC (*(vu16 *)REG_ADDR_MOSAIC)
#define REG_BLDCNT (*(vu16 *)REG_ADDR_BLDCNT)
#define REG_BLDALPHA (*(vu16 *)REG_ADDR_BLDALPHA)
#define REG_BLDY (*(vu16 *)REG_ADDR_BLDY)
#define REG_DISPCNT (*(reg_u16 *)REG_ADDR_DISPCNT)
#define REG_DISPSTAT (*(reg_u16 *)REG_ADDR_DISPSTAT)
#define REG_VCOUNT (*(reg_u16 *)REG_ADDR_VCOUNT)
#define REG_BG0CNT (*(reg_u16 *)REG_ADDR_BG0CNT)
#define REG_BG1CNT (*(reg_u16 *)REG_ADDR_BG1CNT)
#define REG_BG2CNT (*(reg_u16 *)REG_ADDR_BG2CNT)
#define REG_BG3CNT (*(reg_u16 *)REG_ADDR_BG3CNT)
#define REG_BG0HOFS (*(reg_u16 *)REG_ADDR_BG0HOFS)
#define REG_BG0VOFS (*(reg_u16 *)REG_ADDR_BG0VOFS)
#define REG_BG1HOFS (*(reg_u16 *)REG_ADDR_BG1HOFS)
#define REG_BG1VOFS (*(reg_u16 *)REG_ADDR_BG1VOFS)
#define REG_BG2HOFS (*(reg_u16 *)REG_ADDR_BG2HOFS)
#define REG_BG2VOFS (*(reg_u16 *)REG_ADDR_BG2VOFS)
#define REG_BG3HOFS (*(reg_u16 *)REG_ADDR_BG3HOFS)
#define REG_BG3VOFS (*(reg_u16 *)REG_ADDR_BG3VOFS)
#define REG_BG2PA (*(reg_u16 *)REG_ADDR_BG2PA)
#define REG_BG2PB (*(reg_u16 *)REG_ADDR_BG2PB)
#define REG_BG2PC (*(reg_u16 *)REG_ADDR_BG2PC)
#define REG_BG2PD (*(reg_u16 *)REG_ADDR_BG2PD)
#define REG_BG2X (*(reg_u32 *)REG_ADDR_BG2X)
#define REG_BG2X_L (*(reg_u16 *)REG_ADDR_BG2X_L)
#define REG_BG2X_H (*(reg_u16 *)REG_ADDR_BG2X_H)
#define REG_BG2Y (*(reg_u32 *)REG_ADDR_BG2Y)
#define REG_BG2Y_L (*(reg_u16 *)REG_ADDR_BG2Y_L)
#define REG_BG2Y_H (*(reg_u16 *)REG_ADDR_BG2Y_H)
#define REG_BG3PA (*(reg_u16 *)REG_ADDR_BG3PA)
#define REG_BG3PB (*(reg_u16 *)REG_ADDR_BG3PB)
#define REG_BG3PC (*(reg_u16 *)REG_ADDR_BG3PC)
#define REG_BG3PD (*(reg_u16 *)REG_ADDR_BG3PD)
#define REG_BG3X (*(reg_u32 *)REG_ADDR_BG3X)
#define REG_BG3X_L (*(reg_u16 *)REG_ADDR_BG3X_L)
#define REG_BG3X_H (*(reg_u16 *)REG_ADDR_BG3X_H)
#define REG_BG3Y (*(reg_u32 *)REG_ADDR_BG3Y)
#define REG_BG3Y_L (*(reg_u16 *)REG_ADDR_BG3Y_L)
#define REG_BG3Y_H (*(reg_u16 *)REG_ADDR_BG3Y_H)
#define REG_WIN0H (*(reg_wint *)REG_ADDR_WIN0H)
#define REG_WIN1H (*(reg_wint *)REG_ADDR_WIN1H)
#define REG_WIN0V (*(reg_wint *)REG_ADDR_WIN0V)
#define REG_WIN1V (*(reg_wint *)REG_ADDR_WIN1V)
#define REG_WININ (*(reg_wint *)REG_ADDR_WININ)
#define REG_WINOUT (*(reg_wint *)REG_ADDR_WINOUT)
#define REG_MOSAIC (*(reg_u16 *)REG_ADDR_MOSAIC)
#define REG_BLDCNT (*(reg_u16 *)REG_ADDR_BLDCNT)
#define REG_BLDALPHA (*(reg_u16 *)REG_ADDR_BLDALPHA)
#define REG_BLDY (*(reg_u16 *)REG_ADDR_BLDY)
#define REG_SOUND1CNT_L (*(vu16 *)REG_ADDR_SOUND1CNT_L)
#define REG_NR10 (*(vu8 *)REG_ADDR_NR10)
#define REG_SOUND1CNT_H (*(vu16 *)REG_ADDR_SOUND1CNT_H)
#define REG_NR11 (*(vu8 *)REG_ADDR_NR11)
#define REG_NR12 (*(vu8 *)REG_ADDR_NR12)
#define REG_SOUND1CNT_X (*(vu16 *)REG_ADDR_SOUND1CNT_X)
#define REG_NR13 (*(vu8 *)REG_ADDR_NR13)
#define REG_NR14 (*(vu8 *)REG_ADDR_NR14)
#define REG_SOUND2CNT_L (*(vu16 *)REG_ADDR_SOUND2CNT_L)
#define REG_NR21 (*(vu8 *)REG_ADDR_NR21)
#define REG_NR22 (*(vu8 *)REG_ADDR_NR22)
#define REG_SOUND2CNT_H (*(vu16 *)REG_ADDR_SOUND2CNT_H)
#define REG_NR23 (*(vu8 *)REG_ADDR_NR23)
#define REG_NR24 (*(vu8 *)REG_ADDR_NR24)
#define REG_SOUND3CNT_L (*(vu16 *)REG_ADDR_SOUND3CNT_L)
#define REG_NR30 (*(vu8 *)REG_ADDR_NR30)
#define REG_SOUND3CNT_H (*(vu16 *)REG_ADDR_SOUND3CNT_H)
#define REG_NR31 (*(vu8 *)REG_ADDR_NR31)
#define REG_NR32 (*(vu8 *)REG_ADDR_NR32)
#define REG_SOUND3CNT_X (*(vu16 *)REG_ADDR_SOUND3CNT_X)
#define REG_NR33 (*(vu8 *)REG_ADDR_NR33)
#define REG_NR34 (*(vu8 *)REG_ADDR_NR34)
#define REG_SOUND4CNT_L (*(vu16 *)REG_ADDR_SOUND4CNT_L)
#define REG_NR41 (*(vu8 *)REG_ADDR_NR41)
#define REG_NR42 (*(vu8 *)REG_ADDR_NR42)
#define REG_SOUND4CNT_H (*(vu16 *)REG_ADDR_SOUND4CNT_H)
#define REG_NR43 (*(vu8 *)REG_ADDR_NR43)
#define REG_NR44 (*(vu8 *)REG_ADDR_NR44)
#define REG_SOUNDCNT_L (*(vu16 *)REG_ADDR_SOUNDCNT_L)
#define REG_NR50 (*(vu8 *)REG_ADDR_NR50)
#define REG_NR51 (*(vu8 *)REG_ADDR_NR51)
#define REG_SOUNDCNT_H (*(vu16 *)REG_ADDR_SOUNDCNT_H)
#define REG_SOUNDCNT_X (*(vu16 *)REG_ADDR_SOUNDCNT_X)
#define REG_NR52 (*(vu8 *)REG_ADDR_NR52)
#define REG_SOUNDBIAS (*(vu16 *)REG_ADDR_SOUNDBIAS)
#define REG_SOUNDBIAS_L (*(vu8 *)REG_ADDR_SOUNDBIAS_L)
#define REG_SOUNDBIAS_H (*(vu8 *)REG_ADDR_SOUNDBIAS_H)
#define REG_WAVE_RAM0 (*(vu32 *)REG_ADDR_WAVE_RAM0)
#define REG_WAVE_RAM1 (*(vu32 *)REG_ADDR_WAVE_RAM1)
#define REG_WAVE_RAM2 (*(vu32 *)REG_ADDR_WAVE_RAM2)
#define REG_WAVE_RAM3 (*(vu32 *)REG_ADDR_WAVE_RAM3)
#define REG_FIFO_A (*(vu32 *)REG_ADDR_FIFO_A)
#define REG_FIFO_B (*(vu32 *)REG_ADDR_FIFO_B)
#define REG_SOUND1CNT_L (*(reg_u16 *)REG_ADDR_SOUND1CNT_L)
#define REG_NR10 (*(reg_u8 *)REG_ADDR_NR10)
#define REG_SOUND1CNT_H (*(reg_u16 *)REG_ADDR_SOUND1CNT_H)
#define REG_NR11 (*(reg_u8 *)REG_ADDR_NR11)
#define REG_NR12 (*(reg_u8 *)REG_ADDR_NR12)
#define REG_SOUND1CNT_X (*(reg_u16 *)REG_ADDR_SOUND1CNT_X)
#define REG_NR13 (*(reg_u8 *)REG_ADDR_NR13)
#define REG_NR14 (*(reg_u8 *)REG_ADDR_NR14)
#define REG_SOUND2CNT_L (*(reg_u16 *)REG_ADDR_SOUND2CNT_L)
#define REG_NR21 (*(reg_u8 *)REG_ADDR_NR21)
#define REG_NR22 (*(reg_u8 *)REG_ADDR_NR22)
#define REG_SOUND2CNT_H (*(reg_u16 *)REG_ADDR_SOUND2CNT_H)
#define REG_NR23 (*(reg_u8 *)REG_ADDR_NR23)
#define REG_NR24 (*(reg_u8 *)REG_ADDR_NR24)
#define REG_SOUND3CNT_L (*(reg_u16 *)REG_ADDR_SOUND3CNT_L)
#define REG_NR30 (*(reg_u8 *)REG_ADDR_NR30)
#define REG_SOUND3CNT_H (*(reg_u16 *)REG_ADDR_SOUND3CNT_H)
#define REG_NR31 (*(reg_u8 *)REG_ADDR_NR31)
#define REG_NR32 (*(reg_u8 *)REG_ADDR_NR32)
#define REG_SOUND3CNT_X (*(reg_u16 *)REG_ADDR_SOUND3CNT_X)
#define REG_NR33 (*(reg_u8 *)REG_ADDR_NR33)
#define REG_NR34 (*(reg_u8 *)REG_ADDR_NR34)
#define REG_SOUND4CNT_L (*(reg_u16 *)REG_ADDR_SOUND4CNT_L)
#define REG_NR41 (*(reg_u8 *)REG_ADDR_NR41)
#define REG_NR42 (*(reg_u8 *)REG_ADDR_NR42)
#define REG_SOUND4CNT_H (*(reg_u16 *)REG_ADDR_SOUND4CNT_H)
#define REG_NR43 (*(reg_u8 *)REG_ADDR_NR43)
#define REG_NR44 (*(reg_u8 *)REG_ADDR_NR44)
#define REG_SOUNDCNT_L (*(reg_u16 *)REG_ADDR_SOUNDCNT_L)
#define REG_NR50 (*(reg_u8 *)REG_ADDR_NR50)
#define REG_NR51 (*(reg_u8 *)REG_ADDR_NR51)
#define REG_SOUNDCNT_H (*(reg_u16 *)REG_ADDR_SOUNDCNT_H)
#define REG_SOUNDCNT_X (*(reg_u16 *)REG_ADDR_SOUNDCNT_X)
#define REG_NR52 (*(reg_u8 *)REG_ADDR_NR52)
#define REG_SOUNDBIAS (*(reg_u16 *)REG_ADDR_SOUNDBIAS)
#define REG_SOUNDBIAS_L (*(reg_u8 *)REG_ADDR_SOUNDBIAS_L)
#define REG_SOUNDBIAS_H (*(reg_u8 *)REG_ADDR_SOUNDBIAS_H)
#define REG_WAVE_RAM0 (*(reg_u32 *)REG_ADDR_WAVE_RAM0)
#define REG_WAVE_RAM1 (*(reg_u32 *)REG_ADDR_WAVE_RAM1)
#define REG_WAVE_RAM2 (*(reg_u32 *)REG_ADDR_WAVE_RAM2)
#define REG_WAVE_RAM3 (*(reg_u32 *)REG_ADDR_WAVE_RAM3)
#define REG_FIFO_A (*(reg_u32 *)REG_ADDR_FIFO_A)
#define REG_FIFO_B (*(reg_u32 *)REG_ADDR_FIFO_B)
#define REG_DMA0SAD (*(volatile uintptr_t *)REG_ADDR_DMA0SAD)
#define REG_DMA0DAD (*(volatile uintptr_t *)REG_ADDR_DMA0DAD)
#define REG_DMA0CNT (*(vu32 *)REG_ADDR_DMA0CNT)
#define REG_DMA0CNT_L (*(vu16 *)REG_ADDR_DMA0CNT_L)
#define REG_DMA0CNT_H (*(vu16 *)REG_ADDR_DMA0CNT_H)
#define REG_DMA0CNT (*(reg_u32 *)REG_ADDR_DMA0CNT)
#define REG_DMA0CNT_L (*(reg_u16 *)REG_ADDR_DMA0CNT_L)
#define REG_DMA0CNT_H (*(reg_u16 *)REG_ADDR_DMA0CNT_H)
#define REG_DMA1SAD (*(volatile uintptr_t *)REG_ADDR_DMA1SAD)
#define REG_DMA1DAD (*(volatile uintptr_t *)REG_ADDR_DMA1DAD)
#define REG_DMA1CNT (*(vu32 *)REG_ADDR_DMA1CNT)
#define REG_DMA1CNT_L (*(vu16 *)REG_ADDR_DMA1CNT_L)
#define REG_DMA1CNT_H (*(vu16 *)REG_ADDR_DMA1CNT_H)
#define REG_DMA1CNT (*(reg_u32 *)REG_ADDR_DMA1CNT)
#define REG_DMA1CNT_L (*(reg_u16 *)REG_ADDR_DMA1CNT_L)
#define REG_DMA1CNT_H (*(reg_u16 *)REG_ADDR_DMA1CNT_H)
#define REG_DMA2SAD (*(volatile uintptr_t *)REG_ADDR_DMA2SAD)
#define REG_DMA2DAD (*(volatile uintptr_t *)REG_ADDR_DMA2DAD)
#define REG_DMA2CNT (*(vu32 *)REG_ADDR_DMA2CNT)
#define REG_DMA2CNT_L (*(vu16 *)REG_ADDR_DMA2CNT_L)
#define REG_DMA2CNT_H (*(vu16 *)REG_ADDR_DMA2CNT_H)
#define REG_DMA2CNT (*(reg_u32 *)REG_ADDR_DMA2CNT)
#define REG_DMA2CNT_L (*(reg_u16 *)REG_ADDR_DMA2CNT_L)
#define REG_DMA2CNT_H (*(reg_u16 *)REG_ADDR_DMA2CNT_H)
#define REG_DMA3SAD (*(volatile uintptr_t *)REG_ADDR_DMA3SAD)
#define REG_DMA3DAD (*(volatile uintptr_t *)REG_ADDR_DMA3DAD)
#define REG_DMA3CNT (*(vu32 *)REG_ADDR_DMA3CNT)
#define REG_DMA3CNT_L (*(vu16 *)REG_ADDR_DMA3CNT_L)
#define REG_DMA3CNT_H (*(vu16 *)REG_ADDR_DMA3CNT_H)
#define REG_DMA3CNT (*(reg_u32 *)REG_ADDR_DMA3CNT)
#define REG_DMA3CNT_L (*(reg_u16 *)REG_ADDR_DMA3CNT_L)
#define REG_DMA3CNT_H (*(reg_u16 *)REG_ADDR_DMA3CNT_H)
#define REG_TMCNT(n) (*(vu16 *)(REG_ADDR_TMCNT + ((n) * 4)))
#define REG_TM0CNT (*(vu32 *)REG_ADDR_TM0CNT)
#define REG_TM0CNT_L (*(vu16 *)REG_ADDR_TM0CNT_L)
#define REG_TM0CNT_H (*(vu16 *)REG_ADDR_TM0CNT_H)
#define REG_TM1CNT (*(vu32 *)REG_ADDR_TM1CNT)
#define REG_TM1CNT_L (*(vu16 *)REG_ADDR_TM1CNT_L)
#define REG_TM1CNT_H (*(vu16 *)REG_ADDR_TM1CNT_H)
#define REG_TM2CNT (*(vu32 *)REG_ADDR_TM2CNT)
#define REG_TM2CNT_L (*(vu16 *)REG_ADDR_TM2CNT_L)
#define REG_TM2CNT_H (*(vu16 *)REG_ADDR_TM2CNT_H)
#define REG_TM3CNT (*(vu32 *)REG_ADDR_TM3CNT)
#define REG_TM3CNT_L (*(vu16 *)REG_ADDR_TM3CNT_L)
#define REG_TM3CNT_H (*(vu16 *)REG_ADDR_TM3CNT_H)
#define REG_TMCNT(n) (*(reg_u16 *)(REG_ADDR_TMCNT + ((n) * 4)))
#define REG_TM0CNT (*(reg_u32 *)REG_ADDR_TM0CNT)
#define REG_TM0CNT_L (*(reg_u16 *)REG_ADDR_TM0CNT_L)
#define REG_TM0CNT_H (*(reg_u16 *)REG_ADDR_TM0CNT_H)
#define REG_TM1CNT (*(reg_u32 *)REG_ADDR_TM1CNT)
#define REG_TM1CNT_L (*(reg_u16 *)REG_ADDR_TM1CNT_L)
#define REG_TM1CNT_H (*(reg_u16 *)REG_ADDR_TM1CNT_H)
#define REG_TM2CNT (*(reg_u32 *)REG_ADDR_TM2CNT)
#define REG_TM2CNT_L (*(reg_u16 *)REG_ADDR_TM2CNT_L)
#define REG_TM2CNT_H (*(reg_u16 *)REG_ADDR_TM2CNT_H)
#define REG_TM3CNT (*(reg_u32 *)REG_ADDR_TM3CNT)
#define REG_TM3CNT_L (*(reg_u16 *)REG_ADDR_TM3CNT_L)
#define REG_TM3CNT_H (*(reg_u16 *)REG_ADDR_TM3CNT_H)
#define REG_SIOCNT (*(vu16 *)REG_ADDR_SIOCNT)
#define REG_SIOCNT_32 (*(vu32 *)REG_ADDR_SIOCNT)
#define REG_SIODATA8 (*(vu16 *)REG_ADDR_SIODATA8)
#define REG_SIODATA32 (*(vu32 *)REG_ADDR_SIODATA32)
#define REG_SIOMLT_SEND (*(vu16 *)REG_ADDR_SIOMLT_SEND)
#define REG_SIOMLT_RECV (*(vu64 *)REG_ADDR_SIOMLT_RECV)
#define REG_SIOMULTI0 (*(vu16 *)REG_ADDR_SIOMULTI0)
#define REG_SIOMULTI1 (*(vu16 *)REG_ADDR_SIOMULTI1)
#define REG_SIOMULTI2 (*(vu16 *)REG_ADDR_SIOMULTI2)
#define REG_SIOMULTI3 (*(vu16 *)REG_ADDR_SIOMULTI3)
#define REG_SIOCNT (*(reg_u16 *)REG_ADDR_SIOCNT)
#define REG_SIOCNT_32 (*(reg_u32 *)REG_ADDR_SIOCNT)
#define REG_SIODATA8 (*(reg_u16 *)REG_ADDR_SIODATA8)
#define REG_SIODATA32 (*(reg_u32 *)REG_ADDR_SIODATA32)
#define REG_SIOMLT_SEND (*(reg_u16 *)REG_ADDR_SIOMLT_SEND)
#define REG_SIOMLT_RECV (*(reg_u64 *)REG_ADDR_SIOMLT_RECV)
#define REG_SIOMULTI0 (*(reg_u16 *)REG_ADDR_SIOMULTI0)
#define REG_SIOMULTI1 (*(reg_u16 *)REG_ADDR_SIOMULTI1)
#define REG_SIOMULTI2 (*(reg_u16 *)REG_ADDR_SIOMULTI2)
#define REG_SIOMULTI3 (*(reg_u16 *)REG_ADDR_SIOMULTI3)
#define REG_KEYINPUT (*(vu16 *)REG_ADDR_KEYINPUT)
#define REG_KEYCNT (*(vu16 *)REG_ADDR_KEYCNT)
#define REG_KEYINPUT (*(reg_u16 *)REG_ADDR_KEYINPUT)
#define REG_KEYCNT (*(reg_u16 *)REG_ADDR_KEYCNT)
#define REG_RCNT (*(vu16 *)REG_ADDR_RCNT)
#define REG_RCNT (*(reg_u16 *)REG_ADDR_RCNT)
#define REG_IME (*(vu16 *)REG_ADDR_IME)
#define REG_IE (*(vu16 *)REG_ADDR_IE)
#define REG_IF (*(vu16 *)REG_ADDR_IF)
#define REG_IME (*(reg_u16 *)REG_ADDR_IME)
#define REG_IE (*(reg_u16 *)REG_ADDR_IE)
#define REG_IF (*(reg_u16 *)REG_ADDR_IF)
#define REG_WAITCNT (*(vu16 *)REG_ADDR_WAITCNT)
#define REG_WAITCNT (*(reg_u16 *)REG_ADDR_WAITCNT)
// I/O register fields
+7 -3
View File
@@ -20,6 +20,9 @@
typedef struct __attribute__((packed)) name struct_body name;
#endif
#ifdef __PS2__
#include <tamtypes.h>
#else
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
@@ -28,6 +31,7 @@ typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;
typedef int64_t s64;
#endif
#if (GAME == GAME_SA1)
typedef u8 MetatileIndexType;
@@ -38,12 +42,12 @@ typedef u16 MetatileIndexType;
// If the DISPLAY_HEIGHT was >255, scanline effects would break,
// so we have to make this variable bigger.
// (u16 should be plenty for screen coordinates, right?)
#if !defined(DISPLAY_HEIGHT)
#error DISPLAY_HEIGHT not defined.
#if !defined(WIDESCREEN_HACK) && !PLATFORM_GBA
#error WIDESCREEN_HACK not defined.
#endif
/// TODO: Technically this should only be #if (DISPLAY_HEIGHT > 255),
// we should probably replace uses of int_vcount with a different type where a high DISPLAY_WIDTH necessitates u16.
#if ((DISPLAY_WIDTH > 255) || (DISPLAY_HEIGHT > 255))
#if !PLATFORM_GBA && WIDESCREEN_HACK
typedef u16 int_vcount;
#else
typedef u8 int_vcount;
+9 -2
View File
@@ -106,6 +106,13 @@
#define MAX_LINES 0
#endif
typedef s32 fixed8_24;
#define float_to_fp8_24(value) (fixed8_24)((value)*16777216.0f)
#define u32_to_fp8_24(value) ((value) << 24)
#define fp8_24_to_u32(value) ((value) >> 24)
#define fp8_24_to_float(value) (float)((value) / 16777216.0f)
#define fp8_24_fractional_part(value) ((value)&0xFFFFFF)
struct MP2KTrack;
struct MP2KPlayerState;
@@ -185,7 +192,7 @@ struct MixerSource {
u8 padding5;
u32 ct;
float fw;
fixed8_24 fw;
u32 freq;
} sound;
@@ -243,7 +250,7 @@ struct SoundMixerState {
#if PLATFORM_GBA
s8 pcmBuffer[PCM_DMA_BUF_SIZE * 2];
#else
float pcmBuffer[PCM_DMA_BUF_SIZE * 2];
fixed8_24 pcmBuffer[PCM_DMA_BUF_SIZE * 2];
#endif
};
+1 -1
View File
@@ -21,7 +21,7 @@ extern void Platform_RLFree(unsigned char *dest);
extern void Platform_LZDecompressUnsafe(unsigned char *src, unsigned char *dest);
extern void Platform_RLDecompressUnsafe(unsigned char *src, unsigned char *dest);
extern void Platform_QueueAudio(const void *data, u32 numBytes);
extern void Platform_QueueAudio(const s16 *data, u32 numBytes);
extern void Platform_ProcessBackgroundsCopyQueue(void);
// TODO: Re-enable once #include-ing global.h/core.h/sprite.h does not result in compilation errors.
// void Platform_TransformSprite(Sprite *s, SpriteTransform *transform);
+3 -3
View File
@@ -18,9 +18,9 @@ struct AudioCGB {
u8 EnvCounterI[4];
bool8 EnvDir[4];
bool8 DAC[4];
float WAVRAM[32];
fixed8_24 WAVRAM[32];
u16 ch4LFSR[2];
float outBuffer[PCM_DMA_BUF_SIZE * 2];
fixed8_24 outBuffer[PCM_DMA_BUF_SIZE * 2];
};
void cgb_audio_init(u32 rate);
@@ -31,6 +31,6 @@ void cgb_set_length(u8 channel, u8 length);
void cgb_set_envelope(u8 channel, u8 envelope);
void cgb_trigger_note(u8 channel);
void cgb_audio_generate(u16 samplesPerFrame);
float *cgb_get_buffer();
fixed8_24 *cgb_get_buffer();
#endif
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,18 @@
#ifndef GUARD_SW_RENDERER_COMMON_H
#define GUARD_SW_RENDERER_COMMON_H
// shared color math for the gba ppu blend unit
// used by both the normal (multi-pass) and fast (single-pass) software renderers
#include "global.h"
#ifndef TILE_WIDTH
#define TILE_WIDTH 8
#endif
#define VRAM_VIEW_WIDTH (32 * TILE_WIDTH)
#define VRAM_VIEW_HEIGHT (((VRAM_SIZE / TILE_SIZE_4BPP) / 32) * TILE_WIDTH)
extern void gpsp_draw_frame(uint16_t *framebuf);
extern void gpsp_draw_vram_view(uint16_t *framebuf);
#endif // GUARD_SW_RENDERER_COMMON_H
+3
View File
@@ -0,0 +1,3 @@
BOOT2 = cdrom0:\SLUS_054.02;1
VER = 1.00
VMODE = NTSC
+3
View File
@@ -106,6 +106,9 @@ void GameInit(void)
// GameStageStart();
#elif ENABLE_DECOMP_CREDITS
// gCurrentLevel = LEVEL_INDEX(ZONE_4, ACT_1);
// ApplyGameStageSettings();
// GameStageStart();
CreateDecompCreditsScreen(hasProfile);
#else
if (gFlags & FLAGS_NO_FLASH_MEMORY) {
-9
View File
@@ -238,19 +238,10 @@ void sub_806EA04(void)
temp5 = (i - stage->cameraHeight) * temp2 * 2;
*unk1884++ = (Q_16_16_TO_INT(temp) * cos) >> 0x10; // BG2PA
// HACK: in SDL we don't handle these PB and PD values properly
#if PLATFORM_SDL
*unk1884++ = 0;
#else
*unk1884++ = (Q_16_16_TO_INT(temp) * sin) >> 0x10; // BG2PB
#endif
*unk1884++ = (Q_16_16_TO_INT(temp) * -sin) >> 0x10; // BG2PC
#if PLATFORM_SDL
*unk1884++ = 0;
#else
*unk1884++ = (Q_16_16_TO_INT(temp) * cos) >> 0x10; // BG2PD
#endif
x = (Q_16_16_TO_INT(temp5) * sin) + (Q_16_16_TO_INT(temp4) * cos) + stage->q16CameraX;
y = (Q_16_16_TO_INT(temp4) * -sin) + (Q_16_16_TO_INT(temp5) * cos) + stage->q16CameraY;
+5 -1
View File
@@ -941,7 +941,7 @@ NONMATCH("asm/non_matching/game/stage/background/StageBgUpdate_Zone2Acts12.inc",
gFlags |= FLAGS_EXECUTE_HBLANK_COPY;
gHBlankCopyTarget = (void *)REG_ADDR_BG3HOFS;
gHBlankCopySize = 4;
gHBlankCopySize = sizeof(u16) * 2;
cursor = gBgOffsetsHBlankPrimary;
dt = gStageTime * 0x18;
@@ -1202,9 +1202,13 @@ void CreateStageBg_Zone4(void)
gBgScrollRegs[3][0] = 0;
gBgScrollRegs[3][1] = 0;
// Software renderer for these devices are too slow
// to handle these spotlights
#if !defined(__PS2__) && !defined(__PSP__)
if (IS_SINGLE_PLAYER) {
CreateSpotLightBeams();
}
#endif
}
void StageBgUpdate_Zone4Acts12(s32 cameraX, s32 cameraY)
File diff suppressed because it is too large. Load diff
+910
View File
@@ -0,0 +1,910 @@
#include <stdio.h>
#include <stdlib.h>
// PS2 libs
#include <kernel.h>
#include <sifrpc.h>
#include <iopcontrol.h>
#include <sbv_patches.h>
#include <ps2_filesystem_driver.h>
#include <ps2_audio_driver.h>
#include <ps2_joystick_driver.h>
#include <libpad.h>
#include <libmtap.h>
#include <gsKit.h>
#include <audsrv.h>
// Game
#include "global.h"
#include "core.h"
#include "multi_sio.h"
#include "gba/defines.h"
#include "gba/io_reg.h"
#include "gba/types.h"
#include "lib/agb_flash/flash_internal.h"
// Emulation
#include "platform/shared/dma.h"
#include "platform/shared/audio/cgb_audio.h"
#include "platform/shared/video/gpsp_renderer.h"
static GSGLOBAL *gsGlobal;
static GSTEXTURE screen;
ALIGNED(256) uint16_t gameImage[DISPLAY_WIDTH * (DISPLAY_HEIGHT + 1)];
struct VidMode {
const char *name;
s16 mode;
s16 interlace;
s16 field;
int max_width;
int max_height;
int width;
int height;
int vck;
int iPassCount;
int x_off;
int y_off;
};
static const struct VidMode vid_modes[] = {
{ "240p", GS_MODE_NTSC, GS_NONINTERLACED, GS_FRAME, 652, 224, 320, 224, 2, 1, 0, 0 },
#if !defined(VERSION_EU)
// NTSC
{ "480i", GS_MODE_NTSC, GS_INTERLACED, GS_FIELD, 704, 480, 704, 452, 4, 1, 0, 0 },
{ "480p", GS_MODE_DTV_480P, GS_NONINTERLACED, GS_FRAME, 704, 480, 704, 452, 2, 1, 0, 0 },
#else
// PAL
{ "576i", GS_MODE_PAL, GS_INTERLACED, GS_FIELD, 704, 576, 704, 536, 4, 1, 0, 0 },
{ "576p", GS_MODE_DTV_576P, GS_NONINTERLACED, GS_FRAME, 704, 576, 704, 536, 2, 1, 0, 0 },
#endif
// HDTV
{ "720p", GS_MODE_DTV_720P, GS_NONINTERLACED, GS_FRAME, 1280, 720, 1280, 720, 1, 2, 0, 0 },
{ "1080i", GS_MODE_DTV_1080I, GS_INTERLACED, GS_FRAME, 1920, 1080, 1920, 1080, 1, 2, 0, 0 },
};
static const struct VidMode *vid_mode;
static bool use_hires = false;
static u8 padbuf[256] __attribute__((aligned(64)));
static int init_done = 0;
static int joy_port = -1;
static int joy_slot = -1;
static int joy_id = -1;
static struct padButtonStatus joy_buttons __attribute__((aligned(64)));
bool speedUp = false;
bool isRunning = true;
bool paused = false;
bool stepOneFrame = false;
bool headless = false;
double lastGameTime = 0;
double curGameTime = 0;
double fixedTimestep = 1.0 / 60.0; // 16.666667ms
double timeScale = 1.0;
double accumulator = 0.0;
static FILE *sSaveFile = NULL;
extern void AgbMain(void);
void VideoUpdateTexture(void);
static void ReadSaveFile(char *path);
static void StoreSaveFile(void);
static void CloseSaveFile(void);
u16 Platform_GetKeyInput(void);
// Audio
static bool AudioInit(void)
{
if (init_audio_driver() != 0)
return false;
audsrv_set_volume(MAX_VOLUME);
audsrv_fmt_t fmt;
fmt.freq = 48000;
fmt.bits = 16;
fmt.channels = 2;
if (audsrv_set_format(&fmt)) {
printf("audio_ps2: unsupported sound format\n");
audsrv_quit();
return false;
}
return true;
}
static void AudioPlay(const uint8_t *buf, size_t len)
{
if ((audsrv_queued() / 4) < 6000) {
audsrv_play_audio(buf, len);
}
}
// Video
void VideoInit(void)
{
if (vid_mode == NULL) {
vid_mode = &vid_modes[3]; // Standard def 480p
} else {
if (use_hires) {
gsKit_hires_deinit_global(gsGlobal);
} else {
gsKit_deinit_global(gsGlobal);
}
}
use_hires = (vid_mode->mode == GS_MODE_DTV_720P || vid_mode->mode == GS_MODE_DTV_1080I);
if (use_hires) {
gsGlobal = gsKit_hires_init_global();
} else {
gsGlobal = gsKit_init_global();
}
dmaKit_init(D_CTRL_RELE_OFF, D_CTRL_MFD_OFF, D_CTRL_STS_UNSPEC, D_CTRL_STD_OFF, D_CTRL_RCYC_8, 1 << DMA_CHANNEL_GIF);
dmaKit_chan_init(DMA_CHANNEL_GIF);
gsGlobal->Mode = vid_mode->mode;
gsGlobal->Width = vid_mode->width;
gsGlobal->Height = vid_mode->height;
if (gsGlobal->Mode == GS_MODE_DTV_1080I) {
gsGlobal->Height /= 2;
}
gsGlobal->Interlace = vid_mode->interlace;
gsGlobal->Field = vid_mode->field;
gsGlobal->ZBuffering = GS_SETTING_ON;
gsGlobal->DoubleBuffering = GS_SETTING_ON;
gsGlobal->PrimAAEnable = GS_SETTING_OFF;
gsGlobal->Dithering = GS_SETTING_OFF;
gsGlobal->PSM = GS_PSM_CT16;
gsGlobal->PSMZ = GS_PSMZ_16;
if (use_hires) {
gsKit_hires_init_screen(gsGlobal, vid_mode->iPassCount);
} else {
gsKit_init_screen(gsGlobal);
}
// hires sets the texture pointer to the wrong location. Ensure it's correct.
gsGlobal->TexturePointer = gsGlobal->CurrentPointer;
gsKit_TexManager_init(gsGlobal);
screen.Width = DISPLAY_WIDTH;
screen.Height = DISPLAY_HEIGHT;
screen.PSM = GS_PSM_CT16;
screen.Mem = (void *)gameImage;
}
void VideoUpdateTexture(void)
{
gsKit_TexManager_invalidate(gsGlobal, &screen);
gsKit_TexManager_bind(gsGlobal, &screen);
int startX = (gsGlobal->Width);
int startY = (gsGlobal->Height);
gsKit_clear(gsGlobal, GS_SETREG_RGBAQ(0, 0, 0, 0, 0));
gsKit_prim_sprite_texture(gsGlobal, &screen,
0.0f, // X1
0.0f, // Y2
0.0f, // U1
0.0f, // V1
startX, // X2
startY, // Y2
gsGlobal->Width, // U2
gsGlobal->Height, // V2
0, GS_SETREG_RGBAQ(128, 128, 128, 0, 0));
}
// Controller
static inline int WaitPad(int tries)
{
int state = padGetState(joy_port, joy_slot);
if (state == PAD_STATE_DISCONN) {
joy_id = -1;
return -1;
}
while ((state != PAD_STATE_STABLE) && (state != PAD_STATE_FINDCTP1)) {
state = padGetState(joy_port, joy_slot);
if (--tries == 0)
break;
}
return 0;
}
static int DetectPad(void)
{
int id = padInfoMode(joy_port, joy_slot, PAD_MODECURID, 0);
if (id <= 0)
return -1;
const int ext = padInfoMode(joy_port, joy_slot, PAD_MODECUREXID, 0);
if (ext)
id = ext;
printf("ControllerInit: detected pad type %d\n", id);
if (id == PAD_TYPE_DIGITAL || id == PAD_TYPE_DUALSHOCK)
padSetMainMode(joy_port, joy_slot, PAD_MMODE_DUALSHOCK, PAD_MMODE_LOCK);
return id;
}
static void ControllerInit(void)
{
int ret = -1;
// MEMORY CARD already initied SIO2MAN
ret = init_joystick_driver(false);
if (ret != 0) {
printf("ControllerInit: failed to init joystick driver: %d\n", ret);
return;
}
const int numports = padGetPortMax();
// Find the first device connected
for (int port = 0; port < numports && joy_port < 0; ++port) {
if (joy_port == -1 && joy_slot == -1 && mtapPortOpen(port)) {
const int maxslots = padGetSlotMax(port);
for (int slot = 0; slot < maxslots; ++slot) {
if (joy_port == -1 && joy_slot == -1 && padPortOpen(port, slot, padbuf) >= 0) {
joy_port = port;
joy_slot = slot;
printf("ControllerInit: using pad (%d, %d)\n", port, slot);
break;
}
}
}
}
if (joy_slot < 0 || joy_port < 0) {
printf("ControllerInit: could not open a single port\n");
return;
}
init_done = 1;
}
static u16 ControllerRead(void)
{
if (!init_done)
return 0;
if (WaitPad(10) < 0)
return 0; // nothing received
if (joy_id < 0) {
// pad not detected yet, do it
joy_id = DetectPad();
if (joy_id < 0)
return 0; // still nothing
if (WaitPad(10) < 0)
return 0;
}
if (padRead(joy_port, joy_slot, &joy_buttons)) {
return 0xffff ^ joy_buttons.btns;
}
return 0;
}
// PS2 Drivers
void ResetIOP()
{
SifInitRpc(0);
while (!SifIopReset(NULL, 0)) { } // Comment this line if you want to "debug" through ps2link
while (!SifIopSync()) { }
}
static void PrepareIOP()
{
ResetIOP();
SifInitRpc(0);
sbv_patch_enable_lmb();
sbv_patch_disable_prefix_check();
}
static void InitPS2Drivers()
{
init_only_boot_ps2_filesystem_driver();
init_memcard_driver(true);
}
static void deInitPS2Drivers()
{
deinit_memcard_driver(true);
deinit_only_boot_ps2_filesystem_driver();
}
int main(int argc, char **argv)
{
PrepareIOP();
InitPS2Drivers();
// ReadSaveFile("sa2.sav");
// Prevent the multiplayer screen from being drawn ( see core.c:EngineInit() )
REG_RCNT = 0x8000;
REG_KEYINPUT = 0x3FF;
AudioInit();
VideoInit();
ControllerInit();
cgb_audio_init(48000);
VideoUpdateTexture();
// Allow the game loop to take control
AgbMain();
return 0;
}
// GBA callbacks
void VBlankIntrWait(void)
{
#define HANDLE_VBLANK_INTRS() \
({ \
REG_VCOUNT = DISPLAY_HEIGHT + 1; \
REG_DISPSTAT |= INTR_FLAG_VBLANK; \
RunDMAs(DMA_VBLANK); \
if (REG_DISPSTAT & DISPSTAT_VBLANK_INTR) \
gIntrTable[INTR_INDEX_VBLANK](); \
REG_DISPSTAT &= ~INTR_FLAG_VBLANK; \
})
if (headless) {
REG_VCOUNT = DISPLAY_HEIGHT + 1;
HANDLE_VBLANK_INTRS();
return;
}
if (isRunning) {
REG_KEYINPUT = KEYS_MASK ^ Platform_GetKeyInput();
gpsp_draw_frame(gameImage);
VideoUpdateTexture();
HANDLE_VBLANK_INTRS();
if (use_hires) {
gsKit_hires_sync(gsGlobal);
gsKit_hires_flip(gsGlobal);
// TODO: use once released on the SDK
// gsKit_hires_flip_ext(gsGlobal, GSFLIP_RATE_LIMIT_1);
} else {
gsKit_sync_flip(gsGlobal);
gsKit_queue_exec(gsGlobal);
}
gsKit_TexManager_nextFrame(gsGlobal);
return;
}
CloseSaveFile();
deInitPS2Drivers();
exit(0);
#undef HANDLE_VBLANK_INTRS
}
void Platform_StoreSaveFile(void) { StoreSaveFile(); }
s16 convertedAudio[4096];
void Platform_QueueAudio(const s16 *data, uint32_t bytesCount)
{
if (headless) {
return;
}
AudioPlay((uint8_t *)data, bytesCount);
}
u16 Platform_GetKeyInput(void)
{
static struct {
u16 gbaBtn;
u16 sceBtn;
} binds[] = {
{ A_BUTTON, PAD_CROSS }, { B_BUTTON, PAD_SQUARE }, { L_BUTTON, PAD_L2 }, { R_BUTTON, PAD_R2 },
{ L_BUTTON, PAD_L1 }, { R_BUTTON, PAD_R1 }, { START_BUTTON, PAD_START }, { DPAD_LEFT, PAD_LEFT },
{ DPAD_RIGHT, PAD_RIGHT }, { DPAD_UP, PAD_UP }, { DPAD_DOWN, PAD_DOWN },
};
u16 keys = 0;
u16 btns = ControllerRead();
for (int i = 0; i < ARRAY_COUNT(binds); ++i)
if (btns & binds[i].sceBtn)
keys |= binds[i].gbaBtn;
return keys;
}
static void ReadSaveFile(char *path)
{
// Check whether the saveFile exists, and create it if not
sSaveFile = fopen(path, "r+b");
if (sSaveFile == NULL) {
sSaveFile = fopen(path, "w+b");
}
fseek(sSaveFile, 0, SEEK_END);
int fileSize = ftell(sSaveFile);
fseek(sSaveFile, 0, SEEK_SET);
// Only read as many bytes as fit inside the buffer
// or as many bytes as are in the file
int bytesToRead = (fileSize < sizeof(FLASH_BASE)) ? fileSize : sizeof(FLASH_BASE);
int bytesRead = fread(FLASH_BASE, 1, bytesToRead, sSaveFile);
// Fill the buffer if the savefile was just created or smaller than the buffer itself
for (int i = bytesRead; i < sizeof(FLASH_BASE); i++) {
FLASH_BASE[i] = 0xFF;
}
}
static void StoreSaveFile()
{
if (sSaveFile != NULL) {
fseek(sSaveFile, 0, SEEK_SET);
fwrite(FLASH_BASE, 1, sizeof(FLASH_BASE), sSaveFile);
}
}
static void CloseSaveFile()
{
if (sSaveFile != NULL) {
fclose(sSaveFile);
}
}
// BIOS function implementations are based on the VBA-M source code.
// TODO: Link these functions from Libagbsyscall
// safe unaligned access for MIPS
static uint32_t CPUReadMemory(const void *src)
{
uint32_t val;
memcpy(&val, src, sizeof(val));
return val;
}
static void CPUWriteMemory(void *dest, uint32_t val) { memcpy(dest, &val, sizeof(val)); }
static uint16_t CPUReadHalfWord(const void *src)
{
uint16_t val;
memcpy(&val, src, sizeof(val));
return val;
}
static void CPUWriteHalfWord(void *dest, uint16_t val) { memcpy(dest, &val, sizeof(val)); }
static uint8_t CPUReadByte(const void *src) { return *(uint8_t *)src; }
static void CPUWriteByte(void *dest, uint8_t val) { *(uint8_t *)dest = val; }
void CpuSet(const void *src, void *dst, u32 cnt)
{
if (dst == NULL) {
puts("Attempted to CpuSet to NULL\n");
return;
}
int count = cnt & 0x1FFFFF;
const u8 *source = src;
u8 *dest = dst;
// 32-bit ?
if ((cnt >> 26) & 1) {
// assert(((uintptr_t)src & ~3) == (uintptr_t)src);
// assert(((uintptr_t)dst & ~3) == (uintptr_t)dst);
// needed for 32-bit mode!
// source = (u8 *)((uint32_t )source & ~3);
// dest = (u8 *)((uint32_t )dest & ~3);
// fill ?
if ((cnt >> 24) & 1) {
uint32_t value = CPUReadMemory(source);
while (count) {
CPUWriteMemory(dest, value);
dest += 4;
count--;
}
} else {
// copy
while (count) {
CPUWriteMemory(dest, CPUReadMemory(source));
source += 4;
dest += 4;
count--;
}
}
} else {
// No align on 16-bit fill?
// assert(((uintptr_t)src & ~1) == (uintptr_t)src);
// assert(((uintptr_t)dst & ~1) == (uintptr_t)dst);
// 16-bit fill?
if ((cnt >> 24) & 1) {
uint16_t value = CPUReadHalfWord(source);
while (count) {
CPUWriteHalfWord(dest, value);
dest += 2;
count--;
}
} else {
// copy
while (count) {
CPUWriteHalfWord(dest, CPUReadHalfWord(source));
source += 2;
dest += 2;
count--;
}
}
}
}
void CpuFastSet(const void *src, void *dst, u32 cnt)
{
if (dst == NULL) {
puts("Attempted to CpuFastSet to NULL\n");
return;
}
int count = cnt & 0x1FFFFF;
const u8 *source = src;
u8 *dest = dst;
// source = (u8 *)((uint32_t )source & ~3);
// dest = (u8 *)((uint32_t )dest & ~3);
// fill?
if ((cnt >> 24) & 1) {
uint32_t value = CPUReadMemory(source);
while (count > 0) {
// BIOS always transfers 32 bytes at a time
for (int i = 0; i < 8; i++) {
CPUWriteMemory(dest, value);
dest += 4;
}
count -= 8;
}
} else {
// copy
while (count > 0) {
// BIOS always transfers 32 bytes at a time
for (int i = 0; i < 8; i++) {
uint32_t value = CPUReadMemory(source);
CPUWriteMemory(dest, value);
source += 4;
dest += 4;
}
count -= 8;
}
}
}
void LZ77UnCompVram(const void *src_, void *dest_)
{
const u8 *src = (const u8 *)src_;
u8 *dest = dest_;
int destSize = (src[3] << 16) | (src[2] << 8) | src[1];
int srcPos = 4;
int destPos = 0;
for (;;) {
unsigned char flags = src[srcPos++];
for (int i = 0; i < 8; i++) {
if (flags & 0x80) {
int blockSize = (src[srcPos] >> 4) + 3;
int blockDistance = (((src[srcPos] & 0xF) << 8) | src[srcPos + 1]) + 1;
srcPos += 2;
int blockPos = destPos - blockDistance;
// Some Ruby/Sapphire tilesets overflow.
if (destPos + blockSize > destSize) {
blockSize = destSize - destPos;
// fprintf(stderr, "Destination buffer overflow.\n");
puts("Destination buffer overflow.\n");
}
if (blockPos < 0)
goto fail;
for (int j = 0; j < blockSize; j++)
dest[destPos++] = dest[blockPos + j];
} else {
if (destPos >= destSize)
goto fail;
dest[destPos++] = src[srcPos++];
}
if (destPos == destSize) {
return;
}
flags <<= 1;
}
}
fail:
puts("Fatal error while decompressing LZ file.\n");
}
void LZ77UnCompWram(const void *src, void *dst)
{
const uint8_t *source = src;
uint8_t *dest = dst;
uint32_t header = CPUReadMemory(source);
source += 4;
int len = header >> 8;
while (len > 0) {
uint8_t d = CPUReadByte(source++);
if (d) {
for (int i = 0; i < 8; i++) {
if (d & 0x80) {
uint16_t data = CPUReadByte(source++) << 8;
data |= CPUReadByte(source++);
int length = (data >> 12) + 3;
int offset = (data & 0x0FFF);
uint8_t *windowOffset = dest - offset - 1;
for (int i2 = 0; i2 < length; i2++) {
CPUWriteByte(dest++, CPUReadByte(windowOffset++));
len--;
if (len == 0)
return;
}
} else {
CPUWriteByte(dest++, CPUReadByte(source++));
len--;
if (len == 0)
return;
}
d <<= 1;
}
} else {
for (int i = 0; i < 8; i++) {
CPUWriteByte(dest++, CPUReadByte(source++));
len--;
if (len == 0)
return;
}
}
}
}
void RLUnCompWram(const void *src, void *dest)
{
int remaining = CPUReadMemory(src) >> 8;
int blockHeader;
int block;
src += 4;
while (remaining > 0) {
blockHeader = CPUReadByte(src);
src++;
if (blockHeader & 0x80) // Compressed?
{
blockHeader &= 0x7F;
blockHeader += 3;
block = CPUReadByte(src);
src++;
while (blockHeader-- && remaining) {
remaining--;
CPUWriteByte(dest, block);
dest++;
}
} else // Uncompressed
{
blockHeader++;
while (blockHeader-- && remaining) {
remaining--;
u8 byte = CPUReadByte(src);
src++;
CPUWriteByte(dest, byte);
dest++;
}
}
}
}
void RLUnCompVram(const void *src, void *dest)
{
int remaining = CPUReadMemory(src) >> 8;
int padding = (4 - remaining) & 0x3;
int blockHeader;
int block;
int halfWord = 0;
src += 4;
while (remaining > 0) {
blockHeader = CPUReadByte(src);
src++;
if (blockHeader & 0x80) // Compressed?
{
blockHeader &= 0x7F;
blockHeader += 3;
block = CPUReadByte(src);
src++;
while (blockHeader-- && remaining) {
remaining--;
if ((uintptr_t)dest & 1) {
halfWord |= block << 8;
CPUWriteHalfWord((void *)((uintptr_t)dest ^ 1), halfWord);
} else
halfWord = block;
dest++;
}
} else // Uncompressed
{
blockHeader++;
while (blockHeader-- && remaining) {
remaining--;
u8 byte = CPUReadByte(src);
src++;
if ((uintptr_t)dest & 1) {
halfWord |= byte << 8;
CPUWriteHalfWord((void *)((uintptr_t)dest ^ 1), halfWord);
} else
halfWord = byte;
dest++;
}
}
}
if ((uintptr_t)dest & 1) {
padding--;
dest++;
}
for (; padding > 0; padding -= 2, dest += 2)
CPUWriteHalfWord(dest, 0);
}
const s16 sineTable[256]
= { (s16)0x0000, (s16)0x0192, (s16)0x0323, (s16)0x04B5, (s16)0x0645, (s16)0x07D5, (s16)0x0964, (s16)0x0AF1, (s16)0x0C7C, (s16)0x0E05,
(s16)0x0F8C, (s16)0x1111, (s16)0x1294, (s16)0x1413, (s16)0x158F, (s16)0x1708, (s16)0x187D, (s16)0x19EF, (s16)0x1B5D, (s16)0x1CC6,
(s16)0x1E2B, (s16)0x1F8B, (s16)0x20E7, (s16)0x223D, (s16)0x238E, (s16)0x24DA, (s16)0x261F, (s16)0x275F, (s16)0x2899, (s16)0x29CD,
(s16)0x2AFA, (s16)0x2C21, (s16)0x2D41, (s16)0x2E5A, (s16)0x2F6B, (s16)0x3076, (s16)0x3179, (s16)0x3274, (s16)0x3367, (s16)0x3453,
(s16)0x3536, (s16)0x3612, (s16)0x36E5, (s16)0x37AF, (s16)0x3871, (s16)0x392A, (s16)0x39DA, (s16)0x3A82, (s16)0x3B20, (s16)0x3BB6,
(s16)0x3C42, (s16)0x3CC5, (s16)0x3D3E, (s16)0x3DAE, (s16)0x3E14, (s16)0x3E71, (s16)0x3EC5, (s16)0x3F0E, (s16)0x3F4E, (s16)0x3F84,
(s16)0x3FB1, (s16)0x3FD3, (s16)0x3FEC, (s16)0x3FFB, (s16)0x4000, (s16)0x3FFB, (s16)0x3FEC, (s16)0x3FD3, (s16)0x3FB1, (s16)0x3F84,
(s16)0x3F4E, (s16)0x3F0E, (s16)0x3EC5, (s16)0x3E71, (s16)0x3E14, (s16)0x3DAE, (s16)0x3D3E, (s16)0x3CC5, (s16)0x3C42, (s16)0x3BB6,
(s16)0x3B20, (s16)0x3A82, (s16)0x39DA, (s16)0x392A, (s16)0x3871, (s16)0x37AF, (s16)0x36E5, (s16)0x3612, (s16)0x3536, (s16)0x3453,
(s16)0x3367, (s16)0x3274, (s16)0x3179, (s16)0x3076, (s16)0x2F6B, (s16)0x2E5A, (s16)0x2D41, (s16)0x2C21, (s16)0x2AFA, (s16)0x29CD,
(s16)0x2899, (s16)0x275F, (s16)0x261F, (s16)0x24DA, (s16)0x238E, (s16)0x223D, (s16)0x20E7, (s16)0x1F8B, (s16)0x1E2B, (s16)0x1CC6,
(s16)0x1B5D, (s16)0x19EF, (s16)0x187D, (s16)0x1708, (s16)0x158F, (s16)0x1413, (s16)0x1294, (s16)0x1111, (s16)0x0F8C, (s16)0x0E05,
(s16)0x0C7C, (s16)0x0AF1, (s16)0x0964, (s16)0x07D5, (s16)0x0645, (s16)0x04B5, (s16)0x0323, (s16)0x0192, (s16)0x0000, (s16)0xFE6E,
(s16)0xFCDD, (s16)0xFB4B, (s16)0xF9BB, (s16)0xF82B, (s16)0xF69C, (s16)0xF50F, (s16)0xF384, (s16)0xF1FB, (s16)0xF074, (s16)0xEEEF,
(s16)0xED6C, (s16)0xEBED, (s16)0xEA71, (s16)0xE8F8, (s16)0xE783, (s16)0xE611, (s16)0xE4A3, (s16)0xE33A, (s16)0xE1D5, (s16)0xE075,
(s16)0xDF19, (s16)0xDDC3, (s16)0xDC72, (s16)0xDB26, (s16)0xD9E1, (s16)0xD8A1, (s16)0xD767, (s16)0xD633, (s16)0xD506, (s16)0xD3DF,
(s16)0xD2BF, (s16)0xD1A6, (s16)0xD095, (s16)0xCF8A, (s16)0xCE87, (s16)0xCD8C, (s16)0xCC99, (s16)0xCBAD, (s16)0xCACA, (s16)0xC9EE,
(s16)0xC91B, (s16)0xC851, (s16)0xC78F, (s16)0xC6D6, (s16)0xC626, (s16)0xC57E, (s16)0xC4E0, (s16)0xC44A, (s16)0xC3BE, (s16)0xC33B,
(s16)0xC2C2, (s16)0xC252, (s16)0xC1EC, (s16)0xC18F, (s16)0xC13B, (s16)0xC0F2, (s16)0xC0B2, (s16)0xC07C, (s16)0xC04F, (s16)0xC02D,
(s16)0xC014, (s16)0xC005, (s16)0xC000, (s16)0xC005, (s16)0xC014, (s16)0xC02D, (s16)0xC04F, (s16)0xC07C, (s16)0xC0B2, (s16)0xC0F2,
(s16)0xC13B, (s16)0xC18F, (s16)0xC1EC, (s16)0xC252, (s16)0xC2C2, (s16)0xC33B, (s16)0xC3BE, (s16)0xC44A, (s16)0xC4E0, (s16)0xC57E,
(s16)0xC626, (s16)0xC6D6, (s16)0xC78F, (s16)0xC851, (s16)0xC91B, (s16)0xC9EE, (s16)0xCACA, (s16)0xCBAD, (s16)0xCC99, (s16)0xCD8C,
(s16)0xCE87, (s16)0xCF8A, (s16)0xD095, (s16)0xD1A6, (s16)0xD2BF, (s16)0xD3DF, (s16)0xD506, (s16)0xD633, (s16)0xD767, (s16)0xD8A1,
(s16)0xD9E1, (s16)0xDB26, (s16)0xDC72, (s16)0xDDC3, (s16)0xDF19, (s16)0xE075, (s16)0xE1D5, (s16)0xE33A, (s16)0xE4A3, (s16)0xE611,
(s16)0xE783, (s16)0xE8F8, (s16)0xEA71, (s16)0xEBED, (s16)0xED6C, (s16)0xEEEF, (s16)0xF074, (s16)0xF1FB, (s16)0xF384, (s16)0xF50F,
(s16)0xF69C, (s16)0xF82B, (s16)0xF9BB, (s16)0xFB4B, (s16)0xFCDD, (s16)0xFE6E };
void SoftReset(u32 resetFlags) { }
void SoftResetExram(u32 resetFlags) { }
// Following functions taken from mGBA's source
u16 ArcTan(s16 i)
{
s32 a = -((i * i) >> 14);
s32 b = ((0xA9 * a) >> 14) + 0x390;
b = ((b * a) >> 14) + 0x91C;
b = ((b * a) >> 14) + 0xFB6;
b = ((b * a) >> 14) + 0x16AA;
b = ((b * a) >> 14) + 0x2081;
b = ((b * a) >> 14) + 0x3651;
b = ((b * a) >> 14) + 0xA2F9;
return (i * b) >> 16;
}
u16 ArcTan2(s16 x, s16 y)
{
if (!y) {
if (x >= 0)
return 0;
return 0x8000;
}
if (!x) {
if (y >= 0)
return 0x4000;
return 0xC000;
}
if (y >= 0) {
if (x >= 0) {
if (x >= y)
return ArcTan((y << 14) / x);
} else if (-x >= y)
return ArcTan((y << 14) / x) + 0x8000;
return 0x4000 - ArcTan((x << 14) / y);
} else {
if (x <= 0) {
if (-x > -y)
return ArcTan((y << 14) / x) + 0x8000;
} else if (x >= -y)
return ArcTan((y << 14) / x) + 0x10000;
return 0xC000 - ArcTan((x << 14) / y);
}
}
u16 Sqrt(u32 num)
{
if (!num)
return 0;
u32 lower;
u32 upper = num;
u32 bound = 1;
while (bound < upper) {
upper >>= 1;
bound <<= 1;
}
while (1) {
upper = num;
u32 accum = 0;
lower = bound;
while (1) {
u32 oldLower = lower;
if (lower <= upper >> 1)
lower <<= 1;
if (oldLower >= upper >> 1)
break;
}
while (1) {
accum <<= 1;
if (upper >= lower) {
++accum;
upper -= lower;
}
if (lower == bound)
break;
lower >>= 1;
}
u32 oldBound = bound;
bound += accum;
bound >>= 1;
if (bound >= oldBound) {
bound = oldBound;
break;
}
}
return bound;
}
int MultiBoot(struct MultiBootParam *mp) { return 0; }
+65 -53
View File
@@ -3,14 +3,16 @@
#include "platform/shared/audio/cgb_tables.h"
static struct AudioCGB gb;
static float soundChannelPos[4];
static const s16 *PU1Table;
static const s16 *PU2Table;
static fixed8_24 soundChannelPos[4];
static const fixed8_24 *PU1Table;
static const fixed8_24 *PU2Table;
static u32 apuFrame;
static u8 apuCycle;
static u32 sampleRate;
static u16 lfsrMax[2];
float ch4Samples;
fixed8_24 ch4Samples;
fixed8_24 volScale[16];
fixed8_24 ch4StepsScale[12];
void cgb_audio_init(u32 rate)
{
@@ -31,7 +33,7 @@ void cgb_audio_init(u32 rate)
gb.DAC[ch] = 0;
soundChannelPos[ch] = 0;
}
soundChannelPos[1] = 1;
soundChannelPos[1] = u32_to_fp8_24(1);
PU1Table = PU0;
PU2Table = PU0;
sampleRate = rate;
@@ -39,7 +41,12 @@ void cgb_audio_init(u32 rate)
gb.ch4LFSR[1] = 0x80;
lfsrMax[0] = 0x8000;
lfsrMax[1] = 0x80;
ch4Samples = 0.0f;
ch4Samples = 0;
for (int i = 0; i < 16; i++)
volScale[i] = u32_to_fp8_24(i) / 15;
for (int i = 0; i < 12; i++)
ch4StepsScale[i] = u32_to_fp8_24(1) / (i + 1);
}
void cgb_set_sweep(u8 sweep)
@@ -52,8 +59,8 @@ void cgb_set_sweep(u8 sweep)
void cgb_set_wavram()
{
for (u8 wavi = 0; wavi < 0x10; wavi++) {
gb.WAVRAM[(wavi << 1)] = (((*(REG_ADDR_WAVE_RAM0 + wavi)) & 0xF0) >> 4) / 7.5f - 1.0f;
gb.WAVRAM[(wavi << 1) + 1] = (((*(REG_ADDR_WAVE_RAM0 + wavi)) & 0x0F)) / 7.5f - 1.0f;
gb.WAVRAM[(wavi << 1)] = (u32_to_fp8_24(((*(REG_ADDR_WAVE_RAM0 + wavi)) & 0xF0) >> 4) * 2) / 15 - u32_to_fp8_24(1);
gb.WAVRAM[(wavi << 1) + 1] = (u32_to_fp8_24(((*(REG_ADDR_WAVE_RAM0 + wavi)) & 0x0F)) * 2) / 15 - u32_to_fp8_24(1);
}
}
@@ -103,7 +110,7 @@ void cgb_trigger_note(u8 channel)
void cgb_audio_generate(u16 samplesPerFrame)
{
float *outBuffer = gb.outBuffer;
fixed8_24 *outBuffer = gb.outBuffer;
switch (REG_NR11 & 0xC0) {
case 0x00:
PU1Table = PU0;
@@ -193,75 +200,80 @@ void cgb_audio_generate(u16 samplesPerFrame)
}
}
// Sound generation loop
soundChannelPos[0] += freqTable[REG_SOUND1CNT_X & 0x7FF] / (sampleRate / 32);
soundChannelPos[1] += freqTable[REG_SOUND2CNT_H & 0x7FF] / (sampleRate / 32);
soundChannelPos[2] += freqTable[REG_SOUND3CNT_X & 0x7FF] / (sampleRate / 32);
while (soundChannelPos[0] >= 32)
soundChannelPos[0] -= 32;
while (soundChannelPos[1] >= 32)
soundChannelPos[1] -= 32;
while (soundChannelPos[2] >= 32)
soundChannelPos[2] -= 32;
float outputL = 0;
float outputR = 0;
soundChannelPos[0] += freqTable[REG_SOUND1CNT_X & (ARRAY_COUNT(freqTable) - 1)];
soundChannelPos[1] += freqTable[REG_SOUND2CNT_H & (ARRAY_COUNT(freqTable) - 1)];
soundChannelPos[2] += freqTable[REG_SOUND3CNT_X & (ARRAY_COUNT(freqTable) - 1)];
soundChannelPos[0] &= (u32_to_fp8_24(32)) - 1;
soundChannelPos[1] &= (u32_to_fp8_24(32)) - 1;
soundChannelPos[2] &= (u32_to_fp8_24(32)) - 1;
fixed8_24 outputL = 0;
fixed8_24 outputR = 0;
if (REG_NR52 & 0x80) {
if ((gb.DAC[0]) && (REG_NR52 & 0x01)) {
if (REG_NR51 & 0x10)
outputL += gb.Vol[0] * PU1Table[(int)(soundChannelPos[0])] / 15.0f;
outputL += (gb.Vol[0] * PU1Table[fp8_24_to_u32(soundChannelPos[0])]);
if (REG_NR51 & 0x01)
outputR += gb.Vol[0] * PU1Table[(int)(soundChannelPos[0])] / 15.0f;
outputR += (gb.Vol[0] * PU1Table[fp8_24_to_u32(soundChannelPos[0])]);
}
if ((gb.DAC[1]) && (REG_NR52 & 0x02)) {
if (REG_NR51 & 0x20)
outputL += gb.Vol[1] * PU2Table[(int)(soundChannelPos[1])] / 15.0f;
outputL += (gb.Vol[1] * PU2Table[fp8_24_to_u32(soundChannelPos[1])]);
if (REG_NR51 & 0x02)
outputR += gb.Vol[1] * PU2Table[(int)(soundChannelPos[1])] / 15.0f;
outputR += (gb.Vol[1] * PU2Table[fp8_24_to_u32(soundChannelPos[1])]);
}
if ((REG_NR30 & 0x80) && (REG_NR52 & 0x04)) {
if (REG_NR51 & 0x40)
outputL += gb.Vol[2] * gb.WAVRAM[(int)(soundChannelPos[2])] / 4.0f;
outputL += gb.Vol[2] * (gb.WAVRAM[fp8_24_to_u32(soundChannelPos[2])] >> 2);
if (REG_NR51 & 0x04)
outputR += gb.Vol[2] * gb.WAVRAM[(int)(soundChannelPos[2])] / 4.0f;
outputR += gb.Vol[2] * (gb.WAVRAM[fp8_24_to_u32(soundChannelPos[2])] >> 2);
}
if ((gb.DAC[3]) && (REG_NR52 & 0x08)) {
bool32 lfsrMode = ((REG_NR43 & 0x08) == 8);
ch4Samples += freqTableNSE[REG_SOUND4CNT_H & 0xFF] / sampleRate;
int ch4Out = 0;
ch4Samples += freqTableNSE[REG_SOUND4CNT_H & (ARRAY_COUNT(freqTableNSE) - 1)];
s8 ch4Out = 0;
if (gb.ch4LFSR[lfsrMode] & 1) {
ch4Out++;
} else {
ch4Out--;
}
int avgDiv = 1;
while (ch4Samples >= 1) {
avgDiv++;
bool8 lfsrCarry = 0;
if (gb.ch4LFSR[lfsrMode] & 2)
lfsrCarry ^= 1;
gb.ch4LFSR[lfsrMode] >>= 1;
if (gb.ch4LFSR[lfsrMode] & 2)
lfsrCarry ^= 1;
if (lfsrCarry)
gb.ch4LFSR[lfsrMode] |= lfsrMax[lfsrMode];
if (gb.ch4LFSR[lfsrMode] & 1) {
ch4Out++;
} else {
ch4Out--;
}
ch4Samples--;
u8 steps = fp8_24_to_u32(ch4Samples);
ch4Samples = fp8_24_fractional_part(ch4Samples);
u16 lfsr = gb.ch4LFSR[lfsrMode];
u16 lfsrMask = lfsrMax[lfsrMode];
for (u8 i = 0; i < steps; i++) {
// Comments to show what the bit
// manipulation here is representing
// if (gb.ch4LFSR[lfsrMode] & 2)
u16 lfsrCarry = (lfsr >> 1) & 1;
lfsr >>= 1;
// if (gb.ch4LFSR[lfsrMode] & 2)
lfsrCarry ^= (lfsr >> 1) & 1;
// if (lfsrCarry) gb.ch4LFSR[lfsrMode] |= lfsrMax[lfsrMode];
lfsr |= -lfsrCarry & lfsrMask;
// if (gb.ch4LFSR[lfsrMode] & 1)
ch4Out += (lfsr & 1) ? 1 : -1;
}
float sample = ch4Out;
if (avgDiv > 1)
sample /= avgDiv;
gb.ch4LFSR[lfsrMode] = lfsr;
// NOTE: if we convert this to int before multiplying by volume
// the waves sound effect sounds better
fixed8_24 sample = ch4Out * ch4StepsScale[steps];
// Muliply by the sample and then shift to make 8.24 again
if (REG_NR51 & 0x80)
outputL += gb.Vol[3] * sample / 15.0f;
outputL += ((s64)sample * volScale[gb.Vol[3]]) >> 24;
if (REG_NR51 & 0x08)
outputR += gb.Vol[3] * sample / 15.0f;
outputR += ((s64)sample * volScale[gb.Vol[3]]) >> 24;
}
}
outBuffer[0] = outputL * 0.25f;
outBuffer[1] = outputR * 0.25f;
outBuffer[0] = (outputL >> 2);
outBuffer[1] = (outputR >> 2);
}
}
float *cgb_get_buffer() { return gb.outBuffer; }
fixed8_24 *cgb_get_buffer() { return gb.outBuffer; }
+42 -32
View File
@@ -5,9 +5,9 @@
#include "platform/platform.h"
#include "platform/shared/audio/cgb_audio.h"
static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSource *chan, struct WaveData *wav, float *pcmBuffer,
static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSource *chan, struct WaveData *wav, fixed8_24 *pcmBuffer,
u16 samplesPerFrame, float sampleRateReciprocal);
static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 samplesPerFrame, float *pcmBuffer, u8 dmaCounter,
static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 samplesPerFrame, fixed8_24 *pcmBuffer, u8 dmaCounter,
u16 maxBufSize);
static inline bool32 TickEnvelope(struct MixerSource *chan, struct WaveData *wav);
static void ChnVolSetAsm(struct MixerSource *chan, struct MP2KTrack *track);
@@ -25,12 +25,15 @@ static void ChnVolSetAsm(struct MixerSource *chan, struct MP2KTrack *track);
#define FLOOR_DIV_POW2(a, b) ((a) > 0 ? (a) / (b) : (((a) + 1 - (b)) / (b)))
#endif
static float audioBuffer[PCM_DMA_BUF_SIZE];
static s16 audioBuffer[PCM_DMA_BUF_SIZE];
static struct SoundMixerState sSoundInfo = { 0 };
struct SoundMixerState *SOUND_INFO_PTR = &sSoundInfo;
void SoundMain(void)
{
#if !ENABLE_AUDIO
return;
#endif
struct SoundMixerState *mixer = SOUND_INFO_PTR;
if (mixer->lockStatus != ID_NUMBER) {
@@ -54,7 +57,7 @@ void SoundMain(void)
mixer->CgbSound();
s32 samplesPerFrame = mixer->samplesPerFrame;
float *pcmBuffer = mixer->pcmBuffer;
fixed8_24 *pcmBuffer = mixer->pcmBuffer;
s32 dmaCounter = mixer->dmaCounter;
if (dmaCounter > 1) {
@@ -65,7 +68,7 @@ void SoundMain(void)
cgb_audio_generate(samplesPerFrame);
}
static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 samplesPerFrame, float *pcmBuffer, u8 dmaCounter,
static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 samplesPerFrame, fixed8_24 *pcmBuffer, u8 dmaCounter,
u16 maxBufSize)
{
u32 reverb = mixer->reverb;
@@ -73,8 +76,8 @@ static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 sa
// The vanilla reverb effect outputs a mono sound from four sources:
// - L/R channels as they were mixer->framesPerDmaCycle frames ago
// - L/R channels as they were (mixer->framesPerDmaCycle - 1) frames ago
float *tmp1 = pcmBuffer;
float *tmp2;
fixed8_24 *tmp1 = pcmBuffer;
fixed8_24 *tmp2;
if (dmaCounter == 2) {
tmp2 = mixer->pcmBuffer;
} else {
@@ -82,8 +85,8 @@ static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 sa
}
u16 i = 0;
do {
float s = tmp1[0] + tmp1[1] + tmp2[0] + tmp2[1];
s *= ((float)reverb / 512.0f);
fixed8_24 s = tmp1[0] + tmp1[1] + tmp2[0] + tmp2[1];
s = (s * reverb) >> 9;
tmp1[0] = tmp1[1] = s;
tmp1 += 2;
tmp2 += 2;
@@ -92,7 +95,7 @@ static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 sa
// memset(pcmBuffer, 0, samplesPerFrame);
// memset(pcmBuffer + maxBufSize, 0, samplesPerFrame);
for (int i = 0; i < samplesPerFrame; i++) {
float *dst = &pcmBuffer[i * 2];
fixed8_24 *dst = &pcmBuffer[i * 2];
dst[1] = dst[0] = 0.0f;
}
}
@@ -225,7 +228,7 @@ static inline bool32 TickEnvelope(struct MixerSource *chan, struct WaveData *wav
}
}
static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSource *chan, struct WaveData *wav, float *pcmBuffer,
static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSource *chan, struct WaveData *wav, fixed8_24 *pcmBuffer,
u16 samplesPerFrame, float sampleRateReciprocal)
{ /*, [[[]]]) {*/
u8 v = chan->data.sound.envelopeVol * (mixer->masterVol + 1) / 16U;
@@ -240,15 +243,19 @@ static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSour
}
s32 samplesLeftInWav = chan->data.sound.ct;
s8 *current = chan->current;
signed envR = chan->data.sound.envelopeVolR;
signed envL = chan->data.sound.envelopeVolL;
fixed8_24 envR = chan->data.sound.envelopeVolR << 9; // (* 32768)
fixed8_24 envL = chan->data.sound.envelopeVolL << 9;
if (chan->type & TONEDATA_TYPE_CGB) {
for (u16 i = 0; i < samplesPerFrame; i++, pcmBuffer += 2) {
s8 c = *(current++);
pcmBuffer[1] += (c * envR) / 32768.0f;
pcmBuffer[0] += (c * envL) / 32768.0f;
// Creates a value between -32768 and 32768
// So shift by 9 to make this between -1 and 1
// in 8.24
pcmBuffer[1] += (c * envR);
pcmBuffer[0] += (c * envL);
if (--samplesLeftInWav == 0) {
samplesLeftInWav = loopLen;
if (loopLen != 0) {
@@ -263,8 +270,8 @@ static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSour
chan->data.sound.ct = samplesLeftInWav;
chan->current = current;
} else {
float finePos = chan->data.sound.fw;
float romSamplesPerOutputSample = chan->data.sound.freq * sampleRateReciprocal;
fixed8_24 finePos = chan->data.sound.fw;
fixed8_24 romSamplesPerOutputSample = float_to_fp8_24(chan->data.sound.freq * sampleRateReciprocal);
s16 b = current[0];
s16 m = current[1] - b;
@@ -273,15 +280,15 @@ static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSour
for (u16 i = 0; i < samplesPerFrame; i++, pcmBuffer += 2) {
// Use linear interpolation to calculate a value between the current sample in the wav
// and the next sample. Also cancel out the 9.23 stuff
float sample = (finePos * m) + b;
s32 sample = fp8_24_to_u32((s64)finePos * m) + b;
pcmBuffer[1] += (sample * envR) / 32768.0f;
pcmBuffer[0] += (sample * envL) / 32768.0f;
pcmBuffer[1] += (sample * envR);
pcmBuffer[0] += (sample * envL);
finePos += romSamplesPerOutputSample;
u32 newCoarsePos = finePos;
u32 newCoarsePos = fp8_24_to_u32(finePos);
if (newCoarsePos != 0) {
finePos -= (int)finePos;
finePos = fp8_24_fractional_part(finePos);
samplesLeftInWav -= newCoarsePos;
if (samplesLeftInWav <= 0) {
if (loopLen != 0) {
@@ -905,25 +912,28 @@ void m4aSoundVSync(void)
struct SoundMixerState *mixer = SOUND_INFO_PTR;
if (mixer->lockStatus - ID_NUMBER <= 1) {
s32 samplesPerFrame = mixer->samplesPerFrame * 2;
float *m4aBuffer = mixer->pcmBuffer;
float *cgbBuffer = cgb_get_buffer();
fixed8_24 *m4aBuffer = mixer->pcmBuffer;
fixed8_24 *cgbBuffer = cgb_get_buffer();
s32 dmaCounter = mixer->dmaCounter;
bool8 shouldQueue = FALSE;
if (dmaCounter > 1) {
m4aBuffer += samplesPerFrame * (mixer->framesPerDmaCycle - (dmaCounter - 1));
}
for (u32 i = 0; i < samplesPerFrame; i++) {
audioBuffer[i] = m4aBuffer[i] + cgbBuffer[i];
if (audioBuffer[i] != 0) {
shouldQueue = TRUE;
}
// Sample is fixed 8.24 with a value of -1 to 1
// but when we add we divide by 8 to add some headroom
// and make the mix a much more managable volume
fixed8_24 sample = (m4aBuffer[i] + cgbBuffer[i]) >> 3;
// 1 in 8.24 format is 1 << 24
// 32768 is size expected for s16 audio
// 32768 = 1 << 15
// 24 - 15 = 9
audioBuffer[i] = sample >> 9;
}
if (shouldQueue) {
Platform_QueueAudio(audioBuffer, samplesPerFrame * 4);
}
Platform_QueueAudio(audioBuffer, samplesPerFrame * sizeof(s16));
if ((s8)(--mixer->dmaCounter) <= 0)
mixer->dmaCounter = mixer->framesPerDmaCycle;
}
+2 -2
View File
@@ -4,7 +4,7 @@
struct DMATransfer DMAList[DMA_COUNT] = { 0 };
void RunDMAs(u32 type)
void RunDMAs(DmaStartTypes type)
{
for (int dmaNum = 0; dmaNum < DMA_COUNT; dmaNum++) {
struct DMATransfer *dma = &DMAList[dmaNum];
@@ -124,7 +124,7 @@ void DmaStop(int dmaNum)
void DmaWait(int dmaNum)
{
vu32 *ctrlRegs = &REG_DMA0CNT;
vu32 *ctrlRegs = (vu32 *)&REG_DMA0CNT;
#if !USE_NEW_DMA
while (ctrlRegs[dmaNum * 3] & (DMA_ENABLE << 16))
;
+1 -1
View File
@@ -3,8 +3,8 @@
#include <stdio.h>
#include <windows.h>
#include <xinput.h>
#include "gba/io_reg.h"
#include "gba/types.h"
#include "gba/io_reg.h"
#include "platform/shared/input.h"
#define STICK_THRESHOLD 0.5f
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -473,4 +473,4 @@ void *Platform_realloc(void *ptr, size_t numBytes)
}
void Platform_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); }
void Platform_QueueAudio(const u8 *data, u32 numBytes) { }
void Platform_QueueAudio(const s16 *data, u32 numBytes) { }
+3 -3
View File
@@ -9,7 +9,7 @@
#include "animation_commands.h"
#include "platform/platform.h"
#if !PLATFORM_GBA && !PLATFORM_SDL
#if !PLATFORM_GBA && RENDERER != RENDERER_SOFTWARE
extern void Platform_DisplaySprite(Sprite *sprite, u8 oamPaletteNum);
extern void Platform_TransformSprite(Sprite *sprite, SpriteTransform *transform);
#endif
@@ -395,7 +395,7 @@ NONMATCH("asm/non_matching/engine/TransformSprite.inc", void TransformSprite(Spr
// sp24 = s
UnkSpriteStruct big;
const SpriteOffset *dimensions = s->dimensions;
#if PORTABLE && (RENDERER != RENDERER_SOFTWARE)
#if PORTABLE && RENDERER != RENDERER_SOFTWARE
Platform_TransformSprite(s, transform);
return;
#endif
@@ -727,7 +727,7 @@ void DisplaySprite(Sprite *sprite)
oam->split.paletteNum += sprite->palId;
#endif
#if !PLATFORM_GBA && !PLATFORM_SDL
#if !PLATFORM_GBA && RENDERER != RENDERER_SOFTWARE
// TEMP
// Quick hack for getting output in OpenGL test
// The whole function call should be replaced by this!
+1 -1
View File
@@ -31,7 +31,7 @@ SourceFileType GetFileType(std::string& path)
std::string extension = path.substr(pos + 1);
if (extension == "c")
if (extension == "c" || extension == "cc")
return SourceFileType::Cpp;
else if (extension == "s")
return SourceFileType::Asm;