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} FROM mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT}
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 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 WORKDIR /deps
RUN git clone https://github.com/pret/agbcc.git && cd agbcc && ./build.sh RUN git clone https://github.com/pret/agbcc.git && cd agbcc && ./build.sh
+65 -39
View File
@@ -2,39 +2,39 @@ name: CI
on: on:
push: push:
branches: [ main ] branches: [main]
pull_request: pull_request:
pull_request_target: pull_request_target:
jobs: jobs:
format: 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 runs-on: ubuntu-22.04
steps: steps:
- name: Checkout PR - 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 uses: actions/checkout@master
with: with:
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}
- name: Checkout - name: Checkout
if: ${{ github.event_name == 'push' }} if: ${{ github.event_name == 'push' }}
uses: actions/checkout@master uses: actions/checkout@master
- name: Install tools - name: Install tools
run: | run: |
sudo apt update && sudo apt install clang-format-13 sudo apt update && sudo apt install clang-format-13
- name: Check formatting - name: Check formatting
run: | run: |
make check_format make check_format
build-gba: 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}} 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 runs-on: ubuntu-24.04
name: Build GBA (USA) name: Build GBA (USA)
steps: steps:
- name: Checkout PR - 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 uses: actions/checkout@master
with: with:
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}
@@ -42,7 +42,7 @@ jobs:
- name: Checkout - name: Checkout
if: ${{ github.event_name == 'push' }} if: ${{ github.event_name == 'push' }}
uses: actions/checkout@master uses: actions/checkout@master
- name: Checkout gh-pages - name: Checkout gh-pages
if: ${{ github.event_name == 'push' }} if: ${{ github.event_name == 'push' }}
uses: actions/checkout@master uses: actions/checkout@master
@@ -58,7 +58,7 @@ jobs:
- name: Install tools - name: Install tools
run: | 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 python3 -m pip install gitpython
- name: Install agbcc - name: Install agbcc
@@ -120,17 +120,18 @@ jobs:
cwd: "./gh-pages" cwd: "./gh-pages"
add: "reports maps" add: "reports maps"
message: ${{ env.REPORTS_COMMIT_MSG }} message: ${{ env.REPORTS_COMMIT_MSG }}
build-gba-variants: 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}} 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 runs-on: ubuntu-24.04
name: Build GBA (${{ matrix.variant }}) name: Build GBA (${{ matrix.variant }})
strategy: strategy:
matrix: fail-fast: false
matrix:
variant: ["europe", "japan", "japan_vc", "usa_beta"] variant: ["europe", "japan", "japan_vc", "usa_beta"]
steps: steps:
- name: Checkout PR - 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 uses: actions/checkout@master
with: with:
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}
@@ -138,7 +139,7 @@ jobs:
- name: Checkout - name: Checkout
if: ${{ github.event_name == 'push' }} if: ${{ github.event_name == 'push' }}
uses: actions/checkout@master uses: actions/checkout@master
- name: Checkout gh-pages - name: Checkout gh-pages
if: ${{ github.event_name == 'push' }} if: ${{ github.event_name == 'push' }}
uses: actions/checkout@master uses: actions/checkout@master
@@ -154,7 +155,7 @@ jobs:
- name: Install tools - name: Install tools
run: | 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 - name: Install agbcc
run: | run: |
@@ -167,15 +168,16 @@ jobs:
ports: ports:
strategy: strategy:
matrix: fail-fast: false
platform: ["sdl", "sdl_win32", "win32"] matrix:
os: ["ubuntu-22.04", "macos-15"] platform: ["sdl", "sdl_win32", "sdl_psp", "win32", "ps2"]
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}} 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 }} runs-on: ${{ matrix.os }}
name: Build ${{ matrix.platform }} (${{ matrix.os }}) name: Build ${{ matrix.platform }} (${{ matrix.os }})
steps: steps:
- name: Checkout PR - 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 uses: actions/checkout@master
with: with:
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}
@@ -185,34 +187,58 @@ jobs:
uses: actions/checkout@master uses: actions/checkout@master
- name: Install tools (Linux) - name: Install tools (Linux)
if: ${{ matrix.os == 'ubuntu-22.04' }} if: ${{ matrix.os == 'ubuntu-24.04' }}
run: | 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) - name: Install Tools (Macos)
if: ${{ matrix.os == 'macos-15' }} if: ${{ matrix.os == 'macos-15' }}
run: | 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 - name: Install SDL for win32
if: ${{ matrix.platform == 'sdl_win32' }} if: ${{ matrix.platform == 'sdl_win32' }}
run: | run: |
make SDL2.dll 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 }} - name: ${{ matrix.platform }}
run: | run: |
make -j${nproc} ${{ matrix.platform }} make -j${nproc} ${{ matrix.platform }}
test: test:
strategy: strategy:
matrix: matrix:
platform: ["sdl"] 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}} 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 runs-on: ubuntu-24.04
name: TAS Test ${{ matrix.platform }} name: TAS Test ${{ matrix.platform }}
steps: steps:
- name: Checkout PR - 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 uses: actions/checkout@master
with: with:
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}
@@ -223,17 +249,17 @@ jobs:
- name: Install tools - name: Install tools
run: | 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 - name: Install SDL for win32
if: ${{ matrix.platform == 'sdl_win32' }} if: ${{ matrix.platform == 'sdl_win32' }}
run: | run: |
make SDL2.dll make SDL2.dll
- name: Build ${{ matrix.platform }} - name: Build ${{ matrix.platform }}
run: | run: |
make -j${nproc} ${{ matrix.platform }} TAS_TESTING=1 make -j${nproc} ${{ matrix.platform }} TAS_TESTING=1
- name: Run TAS - name: Run TAS
timeout-minutes: 1 timeout-minutes: 1
env: env:
@@ -242,12 +268,12 @@ jobs:
./sa2.${{ matrix.platform }} ./sa2.${{ matrix.platform }}
level_editor: 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}} 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 runs-on: ubuntu-24.04
name: Level editor (BriBaSA) name: Level editor (BriBaSA)
steps: steps:
- name: Checkout PR - 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 uses: actions/checkout@master
with: with:
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}
@@ -259,7 +285,7 @@ jobs:
- name: Install deps - name: Install deps
run: | run: |
sudo apt update && sudo apt install xorg-dev libsdl2-dev sudo apt update && sudo apt install xorg-dev libsdl2-dev
- name: Build - name: Build
run: | run: |
make -j${nproc} bribasa make -j${nproc} bribasa
+6
View File
@@ -85,6 +85,12 @@ libagbsyscall/*.s
*.exe *.exe
*.dll *.dll
*.sdl *.sdl
*.iso
# PSP build outputs
EBOOT.PBP
PARAM.SFO
sa2_debug.log
# third party deps # third party deps
/ext /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 ### Install system requirements
#### On Linux (including WSL) #### On Linux (including WSL)
``` ```bash
sudo apt update 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 #### On MacOS
``` ```bash
brew install libpng sdl2 mingw-w64 arm-none-eabi-gcc 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 ## Building
Clone/Download the repo 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 **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 #### 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. `sa2.sdl` will be created
1. Launch the game from the terminal with `./sa2.sdl` 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 ### GBA rom
1. Clone [agbcc](https://github.com/SAT-R/agbcc) repo into another folder 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/ TOOLCHAIN := /usr/x86_64-w64-mingw32/
PREFIX := x86_64-w64-mingw32- PREFIX := x86_64-w64-mingw32-
endif 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 else
# Native # Native
ifneq ($(PLATFORM),sdl) ifneq ($(PLATFORM),sdl)
@@ -74,6 +82,7 @@ CC1 := tools/agbcc/bin/agbcc$(EXE)
CC1_OLD := tools/agbcc/bin/old_agbcc$(EXE) CC1_OLD := tools/agbcc/bin/old_agbcc$(EXE)
else else
CC1 := $(PREFIX)gcc$(EXE) CC1 := $(PREFIX)gcc$(EXE)
CXX := $(PREFIX)g++$(EXE)
CC1_OLD := $(CC1) CC1_OLD := $(CC1)
endif endif
@@ -120,6 +129,14 @@ else ifeq ($(PLATFORM),sdl)
ROM := $(BUILD_NAME).sdl ROM := $(BUILD_NAME).sdl
ELF := $(ROM).elf ELF := $(ROM).elf
MAP := $(ROM).map 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 else
ROM := $(BUILD_NAME).$(PLATFORM).exe ROM := $(BUILD_NAME).$(PLATFORM).exe
ELF := $(ROM:.exe=.elf) ELF := $(ROM:.exe=.elf)
@@ -156,16 +173,28 @@ TILESETS_SUBDIR = graphics/tilesets/
ifeq ($(PLATFORM),gba) ifeq ($(PLATFORM),gba)
C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/*") C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/*")
else ifeq ($(PLATFORM),sdl) 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) 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) 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 else
C_SRCS := $(shell find $(C_SUBDIR) -name "*.c") C_SRCS := $(shell find $(C_SUBDIR) -name "*.c")
endif endif
C_OBJS := $(patsubst $(C_SUBDIR)/%.c,$(C_BUILDDIR)/%.o,$(C_SRCS)) 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 # Platform not included as we only need the headers for decomp scratches
C_HEADERS := $(shell find $(INCLUDE_DIRS) -name "*.h" -not -path "*/platform/*") 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_SRCS := $(wildcard $(SOUND_ASM_SUBDIR)/*.s)
SOUND_ASM_OBJS := $(patsubst $(SOUND_ASM_SUBDIR)/%.s,$(SOUND_ASM_BUILDDIR)/%.o,$(SOUND_ASM_SRCS)) 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)) OBJS_REL := $(patsubst $(OBJ_DIR)/%,%,$(OBJS))
FORMAT_SRC_PATHS := $(shell find . -name "*.c" ! -path '*/src/data/*' ! -path '*/build/*' ! -path '*/ext/*') FORMAT_SRC_PATHS := $(shell find . -name "*.c" ! -path '*/src/data/*' ! -path '*/build/*' ! -path '*/ext/*')
@@ -225,6 +254,12 @@ else
ifeq ($(PLATFORM),sdl) ifeq ($(PLATFORM),sdl)
CC1FLAGS += -Wno-parentheses-equality -Wno-unused-value 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) 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) 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) 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) else ifeq ($(PLATFORM),win32)
@@ -241,24 +276,18 @@ else
endif endif
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) ifeq ($(DEBUG),1)
CC1FLAGS += -g3 -O0 CC1FLAGS += -g3 -O0
CPPFLAGS += -D DEBUG=1 CPPFLAGS += -D DEBUG=1
else 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 CPPFLAGS += -D DEBUG=0
endif endif
@@ -285,6 +314,26 @@ else
CPPFLAGS += -D ENABLE_DECOMP_CREDITS=1 CPPFLAGS += -D ENABLE_DECOMP_CREDITS=1
endif 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 ### ### LINKER FLAGS ###
# GBA # GBA
@@ -297,7 +346,7 @@ else ifeq ($(PLATFORM),sdl)
else else
MAP_FLAG := -Xlinker -Map= MAP_FLAG := -Xlinker -Map=
endif endif
# Win32 # Win32, PSP, PS2
else else
MAP_FLAG := -Xlinker -Map= MAP_FLAG := -Xlinker -Map=
endif 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) LIBS := $(ROOT_DIR)/tools/agbcc/lib/libgcc.a $(ROOT_DIR)/tools/agbcc/lib/libc.a $(LIBABGSYSCALL_LIBS)
else ifeq ($(PLATFORM),sdl) else ifeq ($(PLATFORM),sdl)
LIBS := $(shell sdl2-config --cflags --libs) 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) else ifeq ($(PLATFORM),sdl_win32)
LIBS := -mwin32 -lkernel32 -lwinmm -lmingw32 -lxinput $(SDL_MINGW_LIBS) LIBS := -mwin32 -lkernel32 -lwinmm -lmingw32 -lxinput $(SDL_MINGW_LIBS)
else ifeq ($(PLATFORM), win32) else ifeq ($(PLATFORM), win32)
@@ -316,7 +369,7 @@ endif
#### MAIN TARGETS #### #### MAIN TARGETS ####
# these commands will run regardless of deps being completed # 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 # Ensure required directories exist
$(shell mkdir -p $(C_BUILDDIR) $(ASM_BUILDDIR) $(DATA_ASM_BUILDDIR) $(SOUND_ASM_BUILDDIR) $(SONG_BUILDDIR) $(MID_BUILDDIR)) $(shell mkdir -p $(C_BUILDDIR) $(ASM_BUILDDIR) $(DATA_ASM_BUILDDIR) $(SOUND_ASM_BUILDDIR) $(SONG_BUILDDIR) $(MID_BUILDDIR))
@@ -397,7 +450,8 @@ clean-tools:
tidy: tidy:
$(RM) -r build/* $(RM) -r build/*
$(RM) SDL2.dll $(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 usa_beta: ; @$(MAKE) GAME_REGION=USA GAME_VARIANT=BETA
@@ -409,6 +463,10 @@ europe: ; @$(MAKE) GAME_REGION=EUROPE
sdl: ; @$(MAKE) PLATFORM=sdl sdl: ; @$(MAKE) PLATFORM=sdl
sdl_psp: ; @$(MAKE) PLATFORM=sdl_psp
ps2: ; @$(MAKE) PLATFORM=ps2
tas_sdl: ; @$(MAKE) sdl TAS_TESTING=1 tas_sdl: ; @$(MAKE) sdl TAS_TESTING=1
sdl_win32: sdl_win32:
@@ -459,7 +517,7 @@ data/mb_chao_garden_japan.gba.lz: data/mb_chao_garden_japan.gba
%.bin: %.aif ; $(AIF) $< $@ %.bin: %.aif ; $(AIF) $< $@
$(ELF): $(OBJS) libagbsyscall $(ELF): $(OBJS)
ifeq ($(PLATFORM),gba) ifeq ($(PLATFORM),gba)
@echo "$(LD) -T $(LDSCRIPT) $(MAP_FLAG) $(MAP) <objects> <lib> -o $@" @echo "$(LD) -T $(LDSCRIPT) $(MAP_FLAG) $(MAP) <objects> <lib> -o $@"
@$(CPP) -P $(CPPFLAGS) $(LDSCRIPT) > $(OBJ_DIR)/$(LDSCRIPT) @$(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)/$@ @cd $(OBJ_DIR) && $(CC1) $(MAP_FLAG)$(ROOT_DIR)/$(MAP) $(OBJS_REL) $(LIBS) -o $(ROOT_DIR)/$@
endif endif
$(ROM): $(ELF)
ifeq ($(PLATFORM),gba) ifeq ($(PLATFORM),gba)
$(ROM): $(ELF) libagbsyscall
$(OBJCOPY) -O binary --pad-to 0x8400000 $< $@ $(OBJCOPY) -O binary --pad-to 0x8400000 $< $@
$(FIX) $@ -p -t"$(TITLE)" -c$(GAME_CODE) -m$(MAKER_CODE) -r$(GAME_REVISION) --silent $(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 $< $@ 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 else
$(OBJCOPY) -O pei-x86-64 $< $@ $(OBJCOPY) -O pei-x86-64 $< $@
endif endif
endif
# Build c sources, and ensure alignment # Build c sources, and ensure alignment
$(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.c $(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.c
@@ -491,11 +568,21 @@ ifeq ($(PLATFORM), gba)
endif endif
@$(AS) $(ASFLAGS) $(C_BUILDDIR)/$*.s -o $@ @$(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 # Scan the src dependencies to determine if any dependent files have changed
$(C_BUILDDIR)/%.d: $(C_SUBDIR)/%.c $(C_BUILDDIR)/%.d: $(C_SUBDIR)/%.c
@$(shell mkdir -p $(shell dirname '$(C_BUILDDIR)/$*.d')) @$(shell mkdir -p $(shell dirname '$(C_BUILDDIR)/$*.d'))
$(SCANINC) -M $@ $(INCLUDE_SCANINC_ARGS) $< $(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) # rule for sources from the src dir (parts of libraries)
$(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.s $(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.s
@echo "$(AS) <flags> -o $@ $<" @echo "$(AS) <flags> -o $@ $<"
@@ -515,6 +602,7 @@ $(DATA_ASM_BUILDDIR)/%.d: $(DATA_ASM_SUBDIR)/%.s
ifneq ($(NODEP),1) ifneq ($(NODEP),1)
-include $(addprefix $(OBJ_DIR)/,$(C_SRCS:.c=.d)) -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)) -include $(addprefix $(OBJ_DIR)/,$(DATA_ASM_SRCS:.s=.d))
endif endif
+3 -1
View File
@@ -24,7 +24,9 @@ It builds the following ROMs:
It can also build: It can also build:
* **sa2.sdl** `make sdl` (Linux/MacOS SDL 64bit port) * **sa2.sdl** `make sdl` (Linux/MacOS SDL 64bit port)
* **sa2.sdl_win32.exe** `make sdl_win32` (Windows 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 ## Current state
+2
View File
@@ -10,6 +10,8 @@
.macro mPtr value .macro mPtr value
#if defined(__aarch64__) || defined(__x86_64__) #if defined(__aarch64__) || defined(__x86_64__)
.quad \value .quad \value
#elif defined(__mips__)
.4byte \value
#else #else
.int \value .int \value
#endif #endif
+1
View File
@@ -63,6 +63,7 @@ MAKER_CODE := 78
BUILD_NAME := sa2 BUILD_NAME := sa2
TITLE := SONICADVANC2 TITLE := SONICADVANC2
GAME_CODE := A2N GAME_CODE := A2N
PS2_GAME_CODE := SLUS_054.02
# Revision # Revision
+3
View File
@@ -42,11 +42,14 @@
#define RENDERER_SOFTWARE 0 #define RENDERER_SOFTWARE 0
#define RENDERER_OPENGL 1 #define RENDERER_OPENGL 1
#define RENDERER_COUNT 2 #define RENDERER_COUNT 2
#ifndef RENDERER
#if PLATFORM_WIN32 && !PLATFORM_SDL #if PLATFORM_WIN32 && !PLATFORM_SDL
// TODO: Only win32 for now // TODO: Only win32 for now
#define RENDERER RENDERER_OPENGL #define RENDERER RENDERER_OPENGL
#else #else
#define RENDERER RENDERER_SOFTWARE #define RENDERER RENDERER_SOFTWARE
#endif #endif
#endif
#endif // GUARD_SA2_CONFIG_H #endif // GUARD_SA2_CONFIG_H
+10
View File
@@ -39,8 +39,18 @@
#define OAM_ENTRY_COUNT 128 #define OAM_ENTRY_COUNT 128
#if PORTABLE #if PORTABLE
// NOTE: Used in gba/types.h, so they have to be defined before the #include // 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_WIDTH 426
#define DISPLAY_HEIGHT 240 #define DISPLAY_HEIGHT 240
#endif
// NOTE: We shouldn't consider WIDESCREEN_HACK a permanent thing. // NOTE: We shouldn't consider WIDESCREEN_HACK a permanent thing.
// This hack should best be removed once there's a "native" platform layer. // This hack should best be removed once there's a "native" platform layer.
+151 -130
View File
@@ -5,6 +5,27 @@
#include <stdint.h> #include <stdint.h>
#endif #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 #define IO_SIZE 0x400
#if !PORTABLE #if !PORTABLE
#define REG_BASE 0x4000000 // I/O register base address #define REG_BASE 0x4000000 // I/O register base address
@@ -369,155 +390,155 @@ extern unsigned char REG_BASE[IO_SIZE];
// I/O registers // I/O registers
#define REG_DISPCNT (*(vu16 *)REG_ADDR_DISPCNT) #define REG_DISPCNT (*(reg_u16 *)REG_ADDR_DISPCNT)
#define REG_DISPSTAT (*(vu16 *)REG_ADDR_DISPSTAT) #define REG_DISPSTAT (*(reg_u16 *)REG_ADDR_DISPSTAT)
#define REG_VCOUNT (*(vu16 *)REG_ADDR_VCOUNT) #define REG_VCOUNT (*(reg_u16 *)REG_ADDR_VCOUNT)
#define REG_BG0CNT (*(vu16 *)REG_ADDR_BG0CNT) #define REG_BG0CNT (*(reg_u16 *)REG_ADDR_BG0CNT)
#define REG_BG1CNT (*(vu16 *)REG_ADDR_BG1CNT) #define REG_BG1CNT (*(reg_u16 *)REG_ADDR_BG1CNT)
#define REG_BG2CNT (*(vu16 *)REG_ADDR_BG2CNT) #define REG_BG2CNT (*(reg_u16 *)REG_ADDR_BG2CNT)
#define REG_BG3CNT (*(vu16 *)REG_ADDR_BG3CNT) #define REG_BG3CNT (*(reg_u16 *)REG_ADDR_BG3CNT)
#define REG_BG0HOFS (*(vu16 *)REG_ADDR_BG0HOFS) #define REG_BG0HOFS (*(reg_u16 *)REG_ADDR_BG0HOFS)
#define REG_BG0VOFS (*(vu16 *)REG_ADDR_BG0VOFS) #define REG_BG0VOFS (*(reg_u16 *)REG_ADDR_BG0VOFS)
#define REG_BG1HOFS (*(vu16 *)REG_ADDR_BG1HOFS) #define REG_BG1HOFS (*(reg_u16 *)REG_ADDR_BG1HOFS)
#define REG_BG1VOFS (*(vu16 *)REG_ADDR_BG1VOFS) #define REG_BG1VOFS (*(reg_u16 *)REG_ADDR_BG1VOFS)
#define REG_BG2HOFS (*(vu16 *)REG_ADDR_BG2HOFS) #define REG_BG2HOFS (*(reg_u16 *)REG_ADDR_BG2HOFS)
#define REG_BG2VOFS (*(vu16 *)REG_ADDR_BG2VOFS) #define REG_BG2VOFS (*(reg_u16 *)REG_ADDR_BG2VOFS)
#define REG_BG3HOFS (*(vu16 *)REG_ADDR_BG3HOFS) #define REG_BG3HOFS (*(reg_u16 *)REG_ADDR_BG3HOFS)
#define REG_BG3VOFS (*(vu16 *)REG_ADDR_BG3VOFS) #define REG_BG3VOFS (*(reg_u16 *)REG_ADDR_BG3VOFS)
#define REG_BG2PA (*(vu16 *)REG_ADDR_BG2PA) #define REG_BG2PA (*(reg_u16 *)REG_ADDR_BG2PA)
#define REG_BG2PB (*(vu16 *)REG_ADDR_BG2PB) #define REG_BG2PB (*(reg_u16 *)REG_ADDR_BG2PB)
#define REG_BG2PC (*(vu16 *)REG_ADDR_BG2PC) #define REG_BG2PC (*(reg_u16 *)REG_ADDR_BG2PC)
#define REG_BG2PD (*(vu16 *)REG_ADDR_BG2PD) #define REG_BG2PD (*(reg_u16 *)REG_ADDR_BG2PD)
#define REG_BG2X (*(vu32 *)REG_ADDR_BG2X) #define REG_BG2X (*(reg_u32 *)REG_ADDR_BG2X)
#define REG_BG2X_L (*(vu16 *)REG_ADDR_BG2X_L) #define REG_BG2X_L (*(reg_u16 *)REG_ADDR_BG2X_L)
#define REG_BG2X_H (*(vu16 *)REG_ADDR_BG2X_H) #define REG_BG2X_H (*(reg_u16 *)REG_ADDR_BG2X_H)
#define REG_BG2Y (*(vu32 *)REG_ADDR_BG2Y) #define REG_BG2Y (*(reg_u32 *)REG_ADDR_BG2Y)
#define REG_BG2Y_L (*(vu16 *)REG_ADDR_BG2Y_L) #define REG_BG2Y_L (*(reg_u16 *)REG_ADDR_BG2Y_L)
#define REG_BG2Y_H (*(vu16 *)REG_ADDR_BG2Y_H) #define REG_BG2Y_H (*(reg_u16 *)REG_ADDR_BG2Y_H)
#define REG_BG3PA (*(vu16 *)REG_ADDR_BG3PA) #define REG_BG3PA (*(reg_u16 *)REG_ADDR_BG3PA)
#define REG_BG3PB (*(vu16 *)REG_ADDR_BG3PB) #define REG_BG3PB (*(reg_u16 *)REG_ADDR_BG3PB)
#define REG_BG3PC (*(vu16 *)REG_ADDR_BG3PC) #define REG_BG3PC (*(reg_u16 *)REG_ADDR_BG3PC)
#define REG_BG3PD (*(vu16 *)REG_ADDR_BG3PD) #define REG_BG3PD (*(reg_u16 *)REG_ADDR_BG3PD)
#define REG_BG3X (*(vu32 *)REG_ADDR_BG3X) #define REG_BG3X (*(reg_u32 *)REG_ADDR_BG3X)
#define REG_BG3X_L (*(vu16 *)REG_ADDR_BG3X_L) #define REG_BG3X_L (*(reg_u16 *)REG_ADDR_BG3X_L)
#define REG_BG3X_H (*(vu16 *)REG_ADDR_BG3X_H) #define REG_BG3X_H (*(reg_u16 *)REG_ADDR_BG3X_H)
#define REG_BG3Y (*(vu32 *)REG_ADDR_BG3Y) #define REG_BG3Y (*(reg_u32 *)REG_ADDR_BG3Y)
#define REG_BG3Y_L (*(vu16 *)REG_ADDR_BG3Y_L) #define REG_BG3Y_L (*(reg_u16 *)REG_ADDR_BG3Y_L)
#define REG_BG3Y_H (*(vu16 *)REG_ADDR_BG3Y_H) #define REG_BG3Y_H (*(reg_u16 *)REG_ADDR_BG3Y_H)
#define REG_WIN0H (*(volatile winreg_t *)REG_ADDR_WIN0H) #define REG_WIN0H (*(reg_wint *)REG_ADDR_WIN0H)
#define REG_WIN1H (*(volatile winreg_t *)REG_ADDR_WIN1H) #define REG_WIN1H (*(reg_wint *)REG_ADDR_WIN1H)
#define REG_WIN0V (*(volatile winreg_t *)REG_ADDR_WIN0V) #define REG_WIN0V (*(reg_wint *)REG_ADDR_WIN0V)
#define REG_WIN1V (*(volatile winreg_t *)REG_ADDR_WIN1V) #define REG_WIN1V (*(reg_wint *)REG_ADDR_WIN1V)
#define REG_WININ (*(volatile winreg_t *)REG_ADDR_WININ) #define REG_WININ (*(reg_wint *)REG_ADDR_WININ)
#define REG_WINOUT (*(volatile winreg_t *)REG_ADDR_WINOUT) #define REG_WINOUT (*(reg_wint *)REG_ADDR_WINOUT)
#define REG_MOSAIC (*(vu16 *)REG_ADDR_MOSAIC) #define REG_MOSAIC (*(reg_u16 *)REG_ADDR_MOSAIC)
#define REG_BLDCNT (*(vu16 *)REG_ADDR_BLDCNT) #define REG_BLDCNT (*(reg_u16 *)REG_ADDR_BLDCNT)
#define REG_BLDALPHA (*(vu16 *)REG_ADDR_BLDALPHA) #define REG_BLDALPHA (*(reg_u16 *)REG_ADDR_BLDALPHA)
#define REG_BLDY (*(vu16 *)REG_ADDR_BLDY) #define REG_BLDY (*(reg_u16 *)REG_ADDR_BLDY)
#define REG_SOUND1CNT_L (*(vu16 *)REG_ADDR_SOUND1CNT_L) #define REG_SOUND1CNT_L (*(reg_u16 *)REG_ADDR_SOUND1CNT_L)
#define REG_NR10 (*(vu8 *)REG_ADDR_NR10) #define REG_NR10 (*(reg_u8 *)REG_ADDR_NR10)
#define REG_SOUND1CNT_H (*(vu16 *)REG_ADDR_SOUND1CNT_H) #define REG_SOUND1CNT_H (*(reg_u16 *)REG_ADDR_SOUND1CNT_H)
#define REG_NR11 (*(vu8 *)REG_ADDR_NR11) #define REG_NR11 (*(reg_u8 *)REG_ADDR_NR11)
#define REG_NR12 (*(vu8 *)REG_ADDR_NR12) #define REG_NR12 (*(reg_u8 *)REG_ADDR_NR12)
#define REG_SOUND1CNT_X (*(vu16 *)REG_ADDR_SOUND1CNT_X) #define REG_SOUND1CNT_X (*(reg_u16 *)REG_ADDR_SOUND1CNT_X)
#define REG_NR13 (*(vu8 *)REG_ADDR_NR13) #define REG_NR13 (*(reg_u8 *)REG_ADDR_NR13)
#define REG_NR14 (*(vu8 *)REG_ADDR_NR14) #define REG_NR14 (*(reg_u8 *)REG_ADDR_NR14)
#define REG_SOUND2CNT_L (*(vu16 *)REG_ADDR_SOUND2CNT_L) #define REG_SOUND2CNT_L (*(reg_u16 *)REG_ADDR_SOUND2CNT_L)
#define REG_NR21 (*(vu8 *)REG_ADDR_NR21) #define REG_NR21 (*(reg_u8 *)REG_ADDR_NR21)
#define REG_NR22 (*(vu8 *)REG_ADDR_NR22) #define REG_NR22 (*(reg_u8 *)REG_ADDR_NR22)
#define REG_SOUND2CNT_H (*(vu16 *)REG_ADDR_SOUND2CNT_H) #define REG_SOUND2CNT_H (*(reg_u16 *)REG_ADDR_SOUND2CNT_H)
#define REG_NR23 (*(vu8 *)REG_ADDR_NR23) #define REG_NR23 (*(reg_u8 *)REG_ADDR_NR23)
#define REG_NR24 (*(vu8 *)REG_ADDR_NR24) #define REG_NR24 (*(reg_u8 *)REG_ADDR_NR24)
#define REG_SOUND3CNT_L (*(vu16 *)REG_ADDR_SOUND3CNT_L) #define REG_SOUND3CNT_L (*(reg_u16 *)REG_ADDR_SOUND3CNT_L)
#define REG_NR30 (*(vu8 *)REG_ADDR_NR30) #define REG_NR30 (*(reg_u8 *)REG_ADDR_NR30)
#define REG_SOUND3CNT_H (*(vu16 *)REG_ADDR_SOUND3CNT_H) #define REG_SOUND3CNT_H (*(reg_u16 *)REG_ADDR_SOUND3CNT_H)
#define REG_NR31 (*(vu8 *)REG_ADDR_NR31) #define REG_NR31 (*(reg_u8 *)REG_ADDR_NR31)
#define REG_NR32 (*(vu8 *)REG_ADDR_NR32) #define REG_NR32 (*(reg_u8 *)REG_ADDR_NR32)
#define REG_SOUND3CNT_X (*(vu16 *)REG_ADDR_SOUND3CNT_X) #define REG_SOUND3CNT_X (*(reg_u16 *)REG_ADDR_SOUND3CNT_X)
#define REG_NR33 (*(vu8 *)REG_ADDR_NR33) #define REG_NR33 (*(reg_u8 *)REG_ADDR_NR33)
#define REG_NR34 (*(vu8 *)REG_ADDR_NR34) #define REG_NR34 (*(reg_u8 *)REG_ADDR_NR34)
#define REG_SOUND4CNT_L (*(vu16 *)REG_ADDR_SOUND4CNT_L) #define REG_SOUND4CNT_L (*(reg_u16 *)REG_ADDR_SOUND4CNT_L)
#define REG_NR41 (*(vu8 *)REG_ADDR_NR41) #define REG_NR41 (*(reg_u8 *)REG_ADDR_NR41)
#define REG_NR42 (*(vu8 *)REG_ADDR_NR42) #define REG_NR42 (*(reg_u8 *)REG_ADDR_NR42)
#define REG_SOUND4CNT_H (*(vu16 *)REG_ADDR_SOUND4CNT_H) #define REG_SOUND4CNT_H (*(reg_u16 *)REG_ADDR_SOUND4CNT_H)
#define REG_NR43 (*(vu8 *)REG_ADDR_NR43) #define REG_NR43 (*(reg_u8 *)REG_ADDR_NR43)
#define REG_NR44 (*(vu8 *)REG_ADDR_NR44) #define REG_NR44 (*(reg_u8 *)REG_ADDR_NR44)
#define REG_SOUNDCNT_L (*(vu16 *)REG_ADDR_SOUNDCNT_L) #define REG_SOUNDCNT_L (*(reg_u16 *)REG_ADDR_SOUNDCNT_L)
#define REG_NR50 (*(vu8 *)REG_ADDR_NR50) #define REG_NR50 (*(reg_u8 *)REG_ADDR_NR50)
#define REG_NR51 (*(vu8 *)REG_ADDR_NR51) #define REG_NR51 (*(reg_u8 *)REG_ADDR_NR51)
#define REG_SOUNDCNT_H (*(vu16 *)REG_ADDR_SOUNDCNT_H) #define REG_SOUNDCNT_H (*(reg_u16 *)REG_ADDR_SOUNDCNT_H)
#define REG_SOUNDCNT_X (*(vu16 *)REG_ADDR_SOUNDCNT_X) #define REG_SOUNDCNT_X (*(reg_u16 *)REG_ADDR_SOUNDCNT_X)
#define REG_NR52 (*(vu8 *)REG_ADDR_NR52) #define REG_NR52 (*(reg_u8 *)REG_ADDR_NR52)
#define REG_SOUNDBIAS (*(vu16 *)REG_ADDR_SOUNDBIAS) #define REG_SOUNDBIAS (*(reg_u16 *)REG_ADDR_SOUNDBIAS)
#define REG_SOUNDBIAS_L (*(vu8 *)REG_ADDR_SOUNDBIAS_L) #define REG_SOUNDBIAS_L (*(reg_u8 *)REG_ADDR_SOUNDBIAS_L)
#define REG_SOUNDBIAS_H (*(vu8 *)REG_ADDR_SOUNDBIAS_H) #define REG_SOUNDBIAS_H (*(reg_u8 *)REG_ADDR_SOUNDBIAS_H)
#define REG_WAVE_RAM0 (*(vu32 *)REG_ADDR_WAVE_RAM0) #define REG_WAVE_RAM0 (*(reg_u32 *)REG_ADDR_WAVE_RAM0)
#define REG_WAVE_RAM1 (*(vu32 *)REG_ADDR_WAVE_RAM1) #define REG_WAVE_RAM1 (*(reg_u32 *)REG_ADDR_WAVE_RAM1)
#define REG_WAVE_RAM2 (*(vu32 *)REG_ADDR_WAVE_RAM2) #define REG_WAVE_RAM2 (*(reg_u32 *)REG_ADDR_WAVE_RAM2)
#define REG_WAVE_RAM3 (*(vu32 *)REG_ADDR_WAVE_RAM3) #define REG_WAVE_RAM3 (*(reg_u32 *)REG_ADDR_WAVE_RAM3)
#define REG_FIFO_A (*(vu32 *)REG_ADDR_FIFO_A) #define REG_FIFO_A (*(reg_u32 *)REG_ADDR_FIFO_A)
#define REG_FIFO_B (*(vu32 *)REG_ADDR_FIFO_B) #define REG_FIFO_B (*(reg_u32 *)REG_ADDR_FIFO_B)
#define REG_DMA0SAD (*(volatile uintptr_t *)REG_ADDR_DMA0SAD) #define REG_DMA0SAD (*(volatile uintptr_t *)REG_ADDR_DMA0SAD)
#define REG_DMA0DAD (*(volatile uintptr_t *)REG_ADDR_DMA0DAD) #define REG_DMA0DAD (*(volatile uintptr_t *)REG_ADDR_DMA0DAD)
#define REG_DMA0CNT (*(vu32 *)REG_ADDR_DMA0CNT) #define REG_DMA0CNT (*(reg_u32 *)REG_ADDR_DMA0CNT)
#define REG_DMA0CNT_L (*(vu16 *)REG_ADDR_DMA0CNT_L) #define REG_DMA0CNT_L (*(reg_u16 *)REG_ADDR_DMA0CNT_L)
#define REG_DMA0CNT_H (*(vu16 *)REG_ADDR_DMA0CNT_H) #define REG_DMA0CNT_H (*(reg_u16 *)REG_ADDR_DMA0CNT_H)
#define REG_DMA1SAD (*(volatile uintptr_t *)REG_ADDR_DMA1SAD) #define REG_DMA1SAD (*(volatile uintptr_t *)REG_ADDR_DMA1SAD)
#define REG_DMA1DAD (*(volatile uintptr_t *)REG_ADDR_DMA1DAD) #define REG_DMA1DAD (*(volatile uintptr_t *)REG_ADDR_DMA1DAD)
#define REG_DMA1CNT (*(vu32 *)REG_ADDR_DMA1CNT) #define REG_DMA1CNT (*(reg_u32 *)REG_ADDR_DMA1CNT)
#define REG_DMA1CNT_L (*(vu16 *)REG_ADDR_DMA1CNT_L) #define REG_DMA1CNT_L (*(reg_u16 *)REG_ADDR_DMA1CNT_L)
#define REG_DMA1CNT_H (*(vu16 *)REG_ADDR_DMA1CNT_H) #define REG_DMA1CNT_H (*(reg_u16 *)REG_ADDR_DMA1CNT_H)
#define REG_DMA2SAD (*(volatile uintptr_t *)REG_ADDR_DMA2SAD) #define REG_DMA2SAD (*(volatile uintptr_t *)REG_ADDR_DMA2SAD)
#define REG_DMA2DAD (*(volatile uintptr_t *)REG_ADDR_DMA2DAD) #define REG_DMA2DAD (*(volatile uintptr_t *)REG_ADDR_DMA2DAD)
#define REG_DMA2CNT (*(vu32 *)REG_ADDR_DMA2CNT) #define REG_DMA2CNT (*(reg_u32 *)REG_ADDR_DMA2CNT)
#define REG_DMA2CNT_L (*(vu16 *)REG_ADDR_DMA2CNT_L) #define REG_DMA2CNT_L (*(reg_u16 *)REG_ADDR_DMA2CNT_L)
#define REG_DMA2CNT_H (*(vu16 *)REG_ADDR_DMA2CNT_H) #define REG_DMA2CNT_H (*(reg_u16 *)REG_ADDR_DMA2CNT_H)
#define REG_DMA3SAD (*(volatile uintptr_t *)REG_ADDR_DMA3SAD) #define REG_DMA3SAD (*(volatile uintptr_t *)REG_ADDR_DMA3SAD)
#define REG_DMA3DAD (*(volatile uintptr_t *)REG_ADDR_DMA3DAD) #define REG_DMA3DAD (*(volatile uintptr_t *)REG_ADDR_DMA3DAD)
#define REG_DMA3CNT (*(vu32 *)REG_ADDR_DMA3CNT) #define REG_DMA3CNT (*(reg_u32 *)REG_ADDR_DMA3CNT)
#define REG_DMA3CNT_L (*(vu16 *)REG_ADDR_DMA3CNT_L) #define REG_DMA3CNT_L (*(reg_u16 *)REG_ADDR_DMA3CNT_L)
#define REG_DMA3CNT_H (*(vu16 *)REG_ADDR_DMA3CNT_H) #define REG_DMA3CNT_H (*(reg_u16 *)REG_ADDR_DMA3CNT_H)
#define REG_TMCNT(n) (*(vu16 *)(REG_ADDR_TMCNT + ((n) * 4))) #define REG_TMCNT(n) (*(reg_u16 *)(REG_ADDR_TMCNT + ((n) * 4)))
#define REG_TM0CNT (*(vu32 *)REG_ADDR_TM0CNT) #define REG_TM0CNT (*(reg_u32 *)REG_ADDR_TM0CNT)
#define REG_TM0CNT_L (*(vu16 *)REG_ADDR_TM0CNT_L) #define REG_TM0CNT_L (*(reg_u16 *)REG_ADDR_TM0CNT_L)
#define REG_TM0CNT_H (*(vu16 *)REG_ADDR_TM0CNT_H) #define REG_TM0CNT_H (*(reg_u16 *)REG_ADDR_TM0CNT_H)
#define REG_TM1CNT (*(vu32 *)REG_ADDR_TM1CNT) #define REG_TM1CNT (*(reg_u32 *)REG_ADDR_TM1CNT)
#define REG_TM1CNT_L (*(vu16 *)REG_ADDR_TM1CNT_L) #define REG_TM1CNT_L (*(reg_u16 *)REG_ADDR_TM1CNT_L)
#define REG_TM1CNT_H (*(vu16 *)REG_ADDR_TM1CNT_H) #define REG_TM1CNT_H (*(reg_u16 *)REG_ADDR_TM1CNT_H)
#define REG_TM2CNT (*(vu32 *)REG_ADDR_TM2CNT) #define REG_TM2CNT (*(reg_u32 *)REG_ADDR_TM2CNT)
#define REG_TM2CNT_L (*(vu16 *)REG_ADDR_TM2CNT_L) #define REG_TM2CNT_L (*(reg_u16 *)REG_ADDR_TM2CNT_L)
#define REG_TM2CNT_H (*(vu16 *)REG_ADDR_TM2CNT_H) #define REG_TM2CNT_H (*(reg_u16 *)REG_ADDR_TM2CNT_H)
#define REG_TM3CNT (*(vu32 *)REG_ADDR_TM3CNT) #define REG_TM3CNT (*(reg_u32 *)REG_ADDR_TM3CNT)
#define REG_TM3CNT_L (*(vu16 *)REG_ADDR_TM3CNT_L) #define REG_TM3CNT_L (*(reg_u16 *)REG_ADDR_TM3CNT_L)
#define REG_TM3CNT_H (*(vu16 *)REG_ADDR_TM3CNT_H) #define REG_TM3CNT_H (*(reg_u16 *)REG_ADDR_TM3CNT_H)
#define REG_SIOCNT (*(vu16 *)REG_ADDR_SIOCNT) #define REG_SIOCNT (*(reg_u16 *)REG_ADDR_SIOCNT)
#define REG_SIOCNT_32 (*(vu32 *)REG_ADDR_SIOCNT) #define REG_SIOCNT_32 (*(reg_u32 *)REG_ADDR_SIOCNT)
#define REG_SIODATA8 (*(vu16 *)REG_ADDR_SIODATA8) #define REG_SIODATA8 (*(reg_u16 *)REG_ADDR_SIODATA8)
#define REG_SIODATA32 (*(vu32 *)REG_ADDR_SIODATA32) #define REG_SIODATA32 (*(reg_u32 *)REG_ADDR_SIODATA32)
#define REG_SIOMLT_SEND (*(vu16 *)REG_ADDR_SIOMLT_SEND) #define REG_SIOMLT_SEND (*(reg_u16 *)REG_ADDR_SIOMLT_SEND)
#define REG_SIOMLT_RECV (*(vu64 *)REG_ADDR_SIOMLT_RECV) #define REG_SIOMLT_RECV (*(reg_u64 *)REG_ADDR_SIOMLT_RECV)
#define REG_SIOMULTI0 (*(vu16 *)REG_ADDR_SIOMULTI0) #define REG_SIOMULTI0 (*(reg_u16 *)REG_ADDR_SIOMULTI0)
#define REG_SIOMULTI1 (*(vu16 *)REG_ADDR_SIOMULTI1) #define REG_SIOMULTI1 (*(reg_u16 *)REG_ADDR_SIOMULTI1)
#define REG_SIOMULTI2 (*(vu16 *)REG_ADDR_SIOMULTI2) #define REG_SIOMULTI2 (*(reg_u16 *)REG_ADDR_SIOMULTI2)
#define REG_SIOMULTI3 (*(vu16 *)REG_ADDR_SIOMULTI3) #define REG_SIOMULTI3 (*(reg_u16 *)REG_ADDR_SIOMULTI3)
#define REG_KEYINPUT (*(vu16 *)REG_ADDR_KEYINPUT) #define REG_KEYINPUT (*(reg_u16 *)REG_ADDR_KEYINPUT)
#define REG_KEYCNT (*(vu16 *)REG_ADDR_KEYCNT) #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_IME (*(reg_u16 *)REG_ADDR_IME)
#define REG_IE (*(vu16 *)REG_ADDR_IE) #define REG_IE (*(reg_u16 *)REG_ADDR_IE)
#define REG_IF (*(vu16 *)REG_ADDR_IF) #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 // I/O register fields
+7 -3
View File
@@ -20,6 +20,9 @@
typedef struct __attribute__((packed)) name struct_body name; typedef struct __attribute__((packed)) name struct_body name;
#endif #endif
#ifdef __PS2__
#include <tamtypes.h>
#else
typedef uint8_t u8; typedef uint8_t u8;
typedef uint16_t u16; typedef uint16_t u16;
typedef uint32_t u32; typedef uint32_t u32;
@@ -28,6 +31,7 @@ typedef int8_t s8;
typedef int16_t s16; typedef int16_t s16;
typedef int32_t s32; typedef int32_t s32;
typedef int64_t s64; typedef int64_t s64;
#endif
#if (GAME == GAME_SA1) #if (GAME == GAME_SA1)
typedef u8 MetatileIndexType; typedef u8 MetatileIndexType;
@@ -38,12 +42,12 @@ typedef u16 MetatileIndexType;
// If the DISPLAY_HEIGHT was >255, scanline effects would break, // If the DISPLAY_HEIGHT was >255, scanline effects would break,
// so we have to make this variable bigger. // so we have to make this variable bigger.
// (u16 should be plenty for screen coordinates, right?) // (u16 should be plenty for screen coordinates, right?)
#if !defined(DISPLAY_HEIGHT) #if !defined(WIDESCREEN_HACK) && !PLATFORM_GBA
#error DISPLAY_HEIGHT not defined. #error WIDESCREEN_HACK not defined.
#endif #endif
/// TODO: Technically this should only be #if (DISPLAY_HEIGHT > 255), /// 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. // 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; typedef u16 int_vcount;
#else #else
typedef u8 int_vcount; typedef u8 int_vcount;
+9 -2
View File
@@ -106,6 +106,13 @@
#define MAX_LINES 0 #define MAX_LINES 0
#endif #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 MP2KTrack;
struct MP2KPlayerState; struct MP2KPlayerState;
@@ -185,7 +192,7 @@ struct MixerSource {
u8 padding5; u8 padding5;
u32 ct; u32 ct;
float fw; fixed8_24 fw;
u32 freq; u32 freq;
} sound; } sound;
@@ -243,7 +250,7 @@ struct SoundMixerState {
#if PLATFORM_GBA #if PLATFORM_GBA
s8 pcmBuffer[PCM_DMA_BUF_SIZE * 2]; s8 pcmBuffer[PCM_DMA_BUF_SIZE * 2];
#else #else
float pcmBuffer[PCM_DMA_BUF_SIZE * 2]; fixed8_24 pcmBuffer[PCM_DMA_BUF_SIZE * 2];
#endif #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_LZDecompressUnsafe(unsigned char *src, unsigned char *dest);
extern void Platform_RLDecompressUnsafe(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); extern void Platform_ProcessBackgroundsCopyQueue(void);
// TODO: Re-enable once #include-ing global.h/core.h/sprite.h does not result in compilation errors. // 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); // void Platform_TransformSprite(Sprite *s, SpriteTransform *transform);
+3 -3
View File
@@ -18,9 +18,9 @@ struct AudioCGB {
u8 EnvCounterI[4]; u8 EnvCounterI[4];
bool8 EnvDir[4]; bool8 EnvDir[4];
bool8 DAC[4]; bool8 DAC[4];
float WAVRAM[32]; fixed8_24 WAVRAM[32];
u16 ch4LFSR[2]; u16 ch4LFSR[2];
float outBuffer[PCM_DMA_BUF_SIZE * 2]; fixed8_24 outBuffer[PCM_DMA_BUF_SIZE * 2];
}; };
void cgb_audio_init(u32 rate); 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_set_envelope(u8 channel, u8 envelope);
void cgb_trigger_note(u8 channel); void cgb_trigger_note(u8 channel);
void cgb_audio_generate(u16 samplesPerFrame); void cgb_audio_generate(u16 samplesPerFrame);
float *cgb_get_buffer(); fixed8_24 *cgb_get_buffer();
#endif #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(); // GameStageStart();
#elif ENABLE_DECOMP_CREDITS #elif ENABLE_DECOMP_CREDITS
// gCurrentLevel = LEVEL_INDEX(ZONE_4, ACT_1);
// ApplyGameStageSettings();
// GameStageStart();
CreateDecompCreditsScreen(hasProfile); CreateDecompCreditsScreen(hasProfile);
#else #else
if (gFlags & FLAGS_NO_FLASH_MEMORY) { if (gFlags & FLAGS_NO_FLASH_MEMORY) {
-9
View File
@@ -238,19 +238,10 @@ void sub_806EA04(void)
temp5 = (i - stage->cameraHeight) * temp2 * 2; temp5 = (i - stage->cameraHeight) * temp2 * 2;
*unk1884++ = (Q_16_16_TO_INT(temp) * cos) >> 0x10; // BG2PA *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 *unk1884++ = (Q_16_16_TO_INT(temp) * sin) >> 0x10; // BG2PB
#endif
*unk1884++ = (Q_16_16_TO_INT(temp) * -sin) >> 0x10; // BG2PC *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 *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; 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; 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; gFlags |= FLAGS_EXECUTE_HBLANK_COPY;
gHBlankCopyTarget = (void *)REG_ADDR_BG3HOFS; gHBlankCopyTarget = (void *)REG_ADDR_BG3HOFS;
gHBlankCopySize = 4; gHBlankCopySize = sizeof(u16) * 2;
cursor = gBgOffsetsHBlankPrimary; cursor = gBgOffsetsHBlankPrimary;
dt = gStageTime * 0x18; dt = gStageTime * 0x18;
@@ -1202,9 +1202,13 @@ void CreateStageBg_Zone4(void)
gBgScrollRegs[3][0] = 0; gBgScrollRegs[3][0] = 0;
gBgScrollRegs[3][1] = 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) { if (IS_SINGLE_PLAYER) {
CreateSpotLightBeams(); CreateSpotLightBeams();
} }
#endif
} }
void StageBgUpdate_Zone4Acts12(s32 cameraX, s32 cameraY) 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" #include "platform/shared/audio/cgb_tables.h"
static struct AudioCGB gb; static struct AudioCGB gb;
static float soundChannelPos[4]; static fixed8_24 soundChannelPos[4];
static const s16 *PU1Table; static const fixed8_24 *PU1Table;
static const s16 *PU2Table; static const fixed8_24 *PU2Table;
static u32 apuFrame; static u32 apuFrame;
static u8 apuCycle; static u8 apuCycle;
static u32 sampleRate; static u32 sampleRate;
static u16 lfsrMax[2]; static u16 lfsrMax[2];
float ch4Samples; fixed8_24 ch4Samples;
fixed8_24 volScale[16];
fixed8_24 ch4StepsScale[12];
void cgb_audio_init(u32 rate) void cgb_audio_init(u32 rate)
{ {
@@ -31,7 +33,7 @@ void cgb_audio_init(u32 rate)
gb.DAC[ch] = 0; gb.DAC[ch] = 0;
soundChannelPos[ch] = 0; soundChannelPos[ch] = 0;
} }
soundChannelPos[1] = 1; soundChannelPos[1] = u32_to_fp8_24(1);
PU1Table = PU0; PU1Table = PU0;
PU2Table = PU0; PU2Table = PU0;
sampleRate = rate; sampleRate = rate;
@@ -39,7 +41,12 @@ void cgb_audio_init(u32 rate)
gb.ch4LFSR[1] = 0x80; gb.ch4LFSR[1] = 0x80;
lfsrMax[0] = 0x8000; lfsrMax[0] = 0x8000;
lfsrMax[1] = 0x80; 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) void cgb_set_sweep(u8 sweep)
@@ -52,8 +59,8 @@ void cgb_set_sweep(u8 sweep)
void cgb_set_wavram() void cgb_set_wavram()
{ {
for (u8 wavi = 0; wavi < 0x10; wavi++) { 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)] = (u32_to_fp8_24(((*(REG_ADDR_WAVE_RAM0 + wavi)) & 0xF0) >> 4) * 2) / 15 - u32_to_fp8_24(1);
gb.WAVRAM[(wavi << 1) + 1] = (((*(REG_ADDR_WAVE_RAM0 + wavi)) & 0x0F)) / 7.5f - 1.0f; 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) void cgb_audio_generate(u16 samplesPerFrame)
{ {
float *outBuffer = gb.outBuffer; fixed8_24 *outBuffer = gb.outBuffer;
switch (REG_NR11 & 0xC0) { switch (REG_NR11 & 0xC0) {
case 0x00: case 0x00:
PU1Table = PU0; PU1Table = PU0;
@@ -193,75 +200,80 @@ void cgb_audio_generate(u16 samplesPerFrame)
} }
} }
// Sound generation loop // Sound generation loop
soundChannelPos[0] += freqTable[REG_SOUND1CNT_X & 0x7FF] / (sampleRate / 32); soundChannelPos[0] += freqTable[REG_SOUND1CNT_X & (ARRAY_COUNT(freqTable) - 1)];
soundChannelPos[1] += freqTable[REG_SOUND2CNT_H & 0x7FF] / (sampleRate / 32); soundChannelPos[1] += freqTable[REG_SOUND2CNT_H & (ARRAY_COUNT(freqTable) - 1)];
soundChannelPos[2] += freqTable[REG_SOUND3CNT_X & 0x7FF] / (sampleRate / 32); soundChannelPos[2] += freqTable[REG_SOUND3CNT_X & (ARRAY_COUNT(freqTable) - 1)];
while (soundChannelPos[0] >= 32)
soundChannelPos[0] -= 32; soundChannelPos[0] &= (u32_to_fp8_24(32)) - 1;
while (soundChannelPos[1] >= 32) soundChannelPos[1] &= (u32_to_fp8_24(32)) - 1;
soundChannelPos[1] -= 32; soundChannelPos[2] &= (u32_to_fp8_24(32)) - 1;
while (soundChannelPos[2] >= 32)
soundChannelPos[2] -= 32; fixed8_24 outputL = 0;
float outputL = 0; fixed8_24 outputR = 0;
float outputR = 0;
if (REG_NR52 & 0x80) { if (REG_NR52 & 0x80) {
if ((gb.DAC[0]) && (REG_NR52 & 0x01)) { if ((gb.DAC[0]) && (REG_NR52 & 0x01)) {
if (REG_NR51 & 0x10) 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) 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 ((gb.DAC[1]) && (REG_NR52 & 0x02)) {
if (REG_NR51 & 0x20) 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) 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_NR30 & 0x80) && (REG_NR52 & 0x04)) {
if (REG_NR51 & 0x40) 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) 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)) { if ((gb.DAC[3]) && (REG_NR52 & 0x08)) {
bool32 lfsrMode = ((REG_NR43 & 0x08) == 8); bool32 lfsrMode = ((REG_NR43 & 0x08) == 8);
ch4Samples += freqTableNSE[REG_SOUND4CNT_H & 0xFF] / sampleRate; ch4Samples += freqTableNSE[REG_SOUND4CNT_H & (ARRAY_COUNT(freqTableNSE) - 1)];
int ch4Out = 0; s8 ch4Out = 0;
if (gb.ch4LFSR[lfsrMode] & 1) { if (gb.ch4LFSR[lfsrMode] & 1) {
ch4Out++; ch4Out++;
} else { } else {
ch4Out--; ch4Out--;
} }
int avgDiv = 1; u8 steps = fp8_24_to_u32(ch4Samples);
while (ch4Samples >= 1) { ch4Samples = fp8_24_fractional_part(ch4Samples);
avgDiv++;
bool8 lfsrCarry = 0; u16 lfsr = gb.ch4LFSR[lfsrMode];
if (gb.ch4LFSR[lfsrMode] & 2) u16 lfsrMask = lfsrMax[lfsrMode];
lfsrCarry ^= 1;
gb.ch4LFSR[lfsrMode] >>= 1; for (u8 i = 0; i < steps; i++) {
if (gb.ch4LFSR[lfsrMode] & 2) // Comments to show what the bit
lfsrCarry ^= 1; // manipulation here is representing
if (lfsrCarry)
gb.ch4LFSR[lfsrMode] |= lfsrMax[lfsrMode]; // if (gb.ch4LFSR[lfsrMode] & 2)
if (gb.ch4LFSR[lfsrMode] & 1) { u16 lfsrCarry = (lfsr >> 1) & 1;
ch4Out++; lfsr >>= 1;
} else { // if (gb.ch4LFSR[lfsrMode] & 2)
ch4Out--; lfsrCarry ^= (lfsr >> 1) & 1;
} // if (lfsrCarry) gb.ch4LFSR[lfsrMode] |= lfsrMax[lfsrMode];
ch4Samples--; lfsr |= -lfsrCarry & lfsrMask;
// if (gb.ch4LFSR[lfsrMode] & 1)
ch4Out += (lfsr & 1) ? 1 : -1;
} }
float sample = ch4Out; gb.ch4LFSR[lfsrMode] = lfsr;
if (avgDiv > 1)
sample /= avgDiv; // 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) if (REG_NR51 & 0x80)
outputL += gb.Vol[3] * sample / 15.0f; outputL += ((s64)sample * volScale[gb.Vol[3]]) >> 24;
if (REG_NR51 & 0x08) 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[0] = (outputL >> 2);
outBuffer[1] = outputR * 0.25f; 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/platform.h"
#include "platform/shared/audio/cgb_audio.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); 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); u16 maxBufSize);
static inline bool32 TickEnvelope(struct MixerSource *chan, struct WaveData *wav); static inline bool32 TickEnvelope(struct MixerSource *chan, struct WaveData *wav);
static void ChnVolSetAsm(struct MixerSource *chan, struct MP2KTrack *track); 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))) #define FLOOR_DIV_POW2(a, b) ((a) > 0 ? (a) / (b) : (((a) + 1 - (b)) / (b)))
#endif #endif
static float audioBuffer[PCM_DMA_BUF_SIZE]; static s16 audioBuffer[PCM_DMA_BUF_SIZE];
static struct SoundMixerState sSoundInfo = { 0 }; static struct SoundMixerState sSoundInfo = { 0 };
struct SoundMixerState *SOUND_INFO_PTR = &sSoundInfo; struct SoundMixerState *SOUND_INFO_PTR = &sSoundInfo;
void SoundMain(void) void SoundMain(void)
{ {
#if !ENABLE_AUDIO
return;
#endif
struct SoundMixerState *mixer = SOUND_INFO_PTR; struct SoundMixerState *mixer = SOUND_INFO_PTR;
if (mixer->lockStatus != ID_NUMBER) { if (mixer->lockStatus != ID_NUMBER) {
@@ -54,7 +57,7 @@ void SoundMain(void)
mixer->CgbSound(); mixer->CgbSound();
s32 samplesPerFrame = mixer->samplesPerFrame; s32 samplesPerFrame = mixer->samplesPerFrame;
float *pcmBuffer = mixer->pcmBuffer; fixed8_24 *pcmBuffer = mixer->pcmBuffer;
s32 dmaCounter = mixer->dmaCounter; s32 dmaCounter = mixer->dmaCounter;
if (dmaCounter > 1) { if (dmaCounter > 1) {
@@ -65,7 +68,7 @@ void SoundMain(void)
cgb_audio_generate(samplesPerFrame); 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) u16 maxBufSize)
{ {
u32 reverb = mixer->reverb; 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: // 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 frames ago
// - L/R channels as they were (mixer->framesPerDmaCycle - 1) frames ago // - L/R channels as they were (mixer->framesPerDmaCycle - 1) frames ago
float *tmp1 = pcmBuffer; fixed8_24 *tmp1 = pcmBuffer;
float *tmp2; fixed8_24 *tmp2;
if (dmaCounter == 2) { if (dmaCounter == 2) {
tmp2 = mixer->pcmBuffer; tmp2 = mixer->pcmBuffer;
} else { } else {
@@ -82,8 +85,8 @@ static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 sa
} }
u16 i = 0; u16 i = 0;
do { do {
float s = tmp1[0] + tmp1[1] + tmp2[0] + tmp2[1]; fixed8_24 s = tmp1[0] + tmp1[1] + tmp2[0] + tmp2[1];
s *= ((float)reverb / 512.0f); s = (s * reverb) >> 9;
tmp1[0] = tmp1[1] = s; tmp1[0] = tmp1[1] = s;
tmp1 += 2; tmp1 += 2;
tmp2 += 2; tmp2 += 2;
@@ -92,7 +95,7 @@ static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 sa
// memset(pcmBuffer, 0, samplesPerFrame); // memset(pcmBuffer, 0, samplesPerFrame);
// memset(pcmBuffer + maxBufSize, 0, samplesPerFrame); // memset(pcmBuffer + maxBufSize, 0, samplesPerFrame);
for (int i = 0; i < samplesPerFrame; i++) { for (int i = 0; i < samplesPerFrame; i++) {
float *dst = &pcmBuffer[i * 2]; fixed8_24 *dst = &pcmBuffer[i * 2];
dst[1] = dst[0] = 0.0f; 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) u16 samplesPerFrame, float sampleRateReciprocal)
{ /*, [[[]]]) {*/ { /*, [[[]]]) {*/
u8 v = chan->data.sound.envelopeVol * (mixer->masterVol + 1) / 16U; 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; s32 samplesLeftInWav = chan->data.sound.ct;
s8 *current = chan->current; 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) { if (chan->type & TONEDATA_TYPE_CGB) {
for (u16 i = 0; i < samplesPerFrame; i++, pcmBuffer += 2) { for (u16 i = 0; i < samplesPerFrame; i++, pcmBuffer += 2) {
s8 c = *(current++); s8 c = *(current++);
pcmBuffer[1] += (c * envR) / 32768.0f; // Creates a value between -32768 and 32768
pcmBuffer[0] += (c * envL) / 32768.0f; // 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) { if (--samplesLeftInWav == 0) {
samplesLeftInWav = loopLen; samplesLeftInWav = loopLen;
if (loopLen != 0) { if (loopLen != 0) {
@@ -263,8 +270,8 @@ static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSour
chan->data.sound.ct = samplesLeftInWav; chan->data.sound.ct = samplesLeftInWav;
chan->current = current; chan->current = current;
} else { } else {
float finePos = chan->data.sound.fw; fixed8_24 finePos = chan->data.sound.fw;
float romSamplesPerOutputSample = chan->data.sound.freq * sampleRateReciprocal; fixed8_24 romSamplesPerOutputSample = float_to_fp8_24(chan->data.sound.freq * sampleRateReciprocal);
s16 b = current[0]; s16 b = current[0];
s16 m = current[1] - b; 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) { for (u16 i = 0; i < samplesPerFrame; i++, pcmBuffer += 2) {
// Use linear interpolation to calculate a value between the current sample in the wav // 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 // 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[1] += (sample * envR);
pcmBuffer[0] += (sample * envL) / 32768.0f; pcmBuffer[0] += (sample * envL);
finePos += romSamplesPerOutputSample; finePos += romSamplesPerOutputSample;
u32 newCoarsePos = finePos; u32 newCoarsePos = fp8_24_to_u32(finePos);
if (newCoarsePos != 0) { if (newCoarsePos != 0) {
finePos -= (int)finePos; finePos = fp8_24_fractional_part(finePos);
samplesLeftInWav -= newCoarsePos; samplesLeftInWav -= newCoarsePos;
if (samplesLeftInWav <= 0) { if (samplesLeftInWav <= 0) {
if (loopLen != 0) { if (loopLen != 0) {
@@ -905,25 +912,28 @@ void m4aSoundVSync(void)
struct SoundMixerState *mixer = SOUND_INFO_PTR; struct SoundMixerState *mixer = SOUND_INFO_PTR;
if (mixer->lockStatus - ID_NUMBER <= 1) { if (mixer->lockStatus - ID_NUMBER <= 1) {
s32 samplesPerFrame = mixer->samplesPerFrame * 2; s32 samplesPerFrame = mixer->samplesPerFrame * 2;
float *m4aBuffer = mixer->pcmBuffer; fixed8_24 *m4aBuffer = mixer->pcmBuffer;
float *cgbBuffer = cgb_get_buffer(); fixed8_24 *cgbBuffer = cgb_get_buffer();
s32 dmaCounter = mixer->dmaCounter; s32 dmaCounter = mixer->dmaCounter;
bool8 shouldQueue = FALSE;
if (dmaCounter > 1) { if (dmaCounter > 1) {
m4aBuffer += samplesPerFrame * (mixer->framesPerDmaCycle - (dmaCounter - 1)); m4aBuffer += samplesPerFrame * (mixer->framesPerDmaCycle - (dmaCounter - 1));
} }
for (u32 i = 0; i < samplesPerFrame; i++) { for (u32 i = 0; i < samplesPerFrame; i++) {
audioBuffer[i] = m4aBuffer[i] + cgbBuffer[i]; // Sample is fixed 8.24 with a value of -1 to 1
if (audioBuffer[i] != 0) { // but when we add we divide by 8 to add some headroom
shouldQueue = TRUE; // 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 * sizeof(s16));
Platform_QueueAudio(audioBuffer, samplesPerFrame * 4);
}
if ((s8)(--mixer->dmaCounter) <= 0) if ((s8)(--mixer->dmaCounter) <= 0)
mixer->dmaCounter = mixer->framesPerDmaCycle; mixer->dmaCounter = mixer->framesPerDmaCycle;
} }
+2 -2
View File
@@ -4,7 +4,7 @@
struct DMATransfer DMAList[DMA_COUNT] = { 0 }; struct DMATransfer DMAList[DMA_COUNT] = { 0 };
void RunDMAs(u32 type) void RunDMAs(DmaStartTypes type)
{ {
for (int dmaNum = 0; dmaNum < DMA_COUNT; dmaNum++) { for (int dmaNum = 0; dmaNum < DMA_COUNT; dmaNum++) {
struct DMATransfer *dma = &DMAList[dmaNum]; struct DMATransfer *dma = &DMAList[dmaNum];
@@ -124,7 +124,7 @@ void DmaStop(int dmaNum)
void DmaWait(int dmaNum) void DmaWait(int dmaNum)
{ {
vu32 *ctrlRegs = &REG_DMA0CNT; vu32 *ctrlRegs = (vu32 *)&REG_DMA0CNT;
#if !USE_NEW_DMA #if !USE_NEW_DMA
while (ctrlRegs[dmaNum * 3] & (DMA_ENABLE << 16)) while (ctrlRegs[dmaNum * 3] & (DMA_ENABLE << 16))
; ;
+1 -1
View File
@@ -3,8 +3,8 @@
#include <stdio.h> #include <stdio.h>
#include <windows.h> #include <windows.h>
#include <xinput.h> #include <xinput.h>
#include "gba/io_reg.h"
#include "gba/types.h" #include "gba/types.h"
#include "gba/io_reg.h"
#include "platform/shared/input.h" #include "platform/shared/input.h"
#define STICK_THRESHOLD 0.5f #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_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 "animation_commands.h"
#include "platform/platform.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_DisplaySprite(Sprite *sprite, u8 oamPaletteNum);
extern void Platform_TransformSprite(Sprite *sprite, SpriteTransform *transform); extern void Platform_TransformSprite(Sprite *sprite, SpriteTransform *transform);
#endif #endif
@@ -395,7 +395,7 @@ NONMATCH("asm/non_matching/engine/TransformSprite.inc", void TransformSprite(Spr
// sp24 = s // sp24 = s
UnkSpriteStruct big; UnkSpriteStruct big;
const SpriteOffset *dimensions = s->dimensions; const SpriteOffset *dimensions = s->dimensions;
#if PORTABLE && (RENDERER != RENDERER_SOFTWARE) #if PORTABLE && RENDERER != RENDERER_SOFTWARE
Platform_TransformSprite(s, transform); Platform_TransformSprite(s, transform);
return; return;
#endif #endif
@@ -727,7 +727,7 @@ void DisplaySprite(Sprite *sprite)
oam->split.paletteNum += sprite->palId; oam->split.paletteNum += sprite->palId;
#endif #endif
#if !PLATFORM_GBA && !PLATFORM_SDL #if !PLATFORM_GBA && RENDERER != RENDERER_SOFTWARE
// TEMP // TEMP
// Quick hack for getting output in OpenGL test // Quick hack for getting output in OpenGL test
// The whole function call should be replaced by this! // 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); std::string extension = path.substr(pos + 1);
if (extension == "c") if (extension == "c" || extension == "cc")
return SourceFileType::Cpp; return SourceFileType::Cpp;
else if (extension == "s") else if (extension == "s")
return SourceFileType::Asm; return SourceFileType::Asm;