mirror of
https://github.com/SAT-R/sa2.git
synced 2026-10-28 09:43:38 +00:00
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:
1 parent
320f536014
commit
59706b53c1
31 files changed
+6332
-3348
No files matched your search
@@ -5,7 +5,7 @@ ARG VARIANT
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT}
|
||||
|
||||
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||
&& apt-get -y install --no-install-recommends binutils-arm-none-eabi gcc-arm-none-eabi libpng-dev build-essential clang-format-13 xorg-dev libsdl2-dev gcc-mingw-w64 libarchive-tools
|
||||
&& apt-get -y install --no-install-recommends binutils-arm-none-eabi gcc-arm-none-eabi libpng-dev build-essential clang-format-13 xorg-dev libsdl2-dev g++-mingw-w64 gcc-mingw-w64 libarchive-tools
|
||||
|
||||
WORKDIR /deps
|
||||
RUN git clone https://github.com/pret/agbcc.git && cd agbcc && ./build.sh
|
||||
+65
-39
@@ -2,39 +2,39 @@ name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
branches: [main]
|
||||
pull_request:
|
||||
pull_request_target:
|
||||
|
||||
jobs:
|
||||
format:
|
||||
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}}
|
||||
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}}
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout PR
|
||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}}
|
||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}}
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Checkout
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
uses: actions/checkout@master
|
||||
|
||||
|
||||
- name: Install tools
|
||||
run: |
|
||||
sudo apt update && sudo apt install clang-format-13
|
||||
|
||||
|
||||
- name: Check formatting
|
||||
run: |
|
||||
make check_format
|
||||
|
||||
build-gba:
|
||||
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}}
|
||||
runs-on: ubuntu-22.04
|
||||
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}}
|
||||
runs-on: ubuntu-24.04
|
||||
name: Build GBA (USA)
|
||||
steps:
|
||||
- name: Checkout PR
|
||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}}
|
||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}}
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
- name: Checkout
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
uses: actions/checkout@master
|
||||
|
||||
|
||||
- name: Checkout gh-pages
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
uses: actions/checkout@master
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
|
||||
- name: Install tools
|
||||
run: |
|
||||
sudo apt update && sudo apt install gcc-arm-none-eabi binutils-arm-none-eabi
|
||||
sudo apt update && sudo apt install gcc-arm-none-eabi binutils-arm-none-eabi libpng-dev
|
||||
python3 -m pip install gitpython
|
||||
|
||||
- name: Install agbcc
|
||||
@@ -120,17 +120,18 @@ jobs:
|
||||
cwd: "./gh-pages"
|
||||
add: "reports maps"
|
||||
message: ${{ env.REPORTS_COMMIT_MSG }}
|
||||
|
||||
|
||||
build-gba-variants:
|
||||
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}}
|
||||
runs-on: ubuntu-22.04
|
||||
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}}
|
||||
runs-on: ubuntu-24.04
|
||||
name: Build GBA (${{ matrix.variant }})
|
||||
strategy:
|
||||
matrix:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
variant: ["europe", "japan", "japan_vc", "usa_beta"]
|
||||
steps:
|
||||
- name: Checkout PR
|
||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}}
|
||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}}
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
@@ -138,7 +139,7 @@ jobs:
|
||||
- name: Checkout
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
uses: actions/checkout@master
|
||||
|
||||
|
||||
- name: Checkout gh-pages
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
uses: actions/checkout@master
|
||||
@@ -154,7 +155,7 @@ jobs:
|
||||
|
||||
- name: Install tools
|
||||
run: |
|
||||
sudo apt update && sudo apt install binutils-arm-none-eabi gcc-arm-none-eabi
|
||||
sudo apt update && sudo apt install binutils-arm-none-eabi gcc-arm-none-eabi libpng-dev
|
||||
|
||||
- name: Install agbcc
|
||||
run: |
|
||||
@@ -167,15 +168,16 @@ jobs:
|
||||
|
||||
ports:
|
||||
strategy:
|
||||
matrix:
|
||||
platform: ["sdl", "sdl_win32", "win32"]
|
||||
os: ["ubuntu-22.04", "macos-15"]
|
||||
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}}
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: ["sdl", "sdl_win32", "sdl_psp", "win32", "ps2"]
|
||||
os: ["ubuntu-24.04", "macos-15"]
|
||||
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}}
|
||||
runs-on: ${{ matrix.os }}
|
||||
name: Build ${{ matrix.platform }} (${{ matrix.os }})
|
||||
steps:
|
||||
- name: Checkout PR
|
||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}}
|
||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}}
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
@@ -185,34 +187,58 @@ jobs:
|
||||
uses: actions/checkout@master
|
||||
|
||||
- name: Install tools (Linux)
|
||||
if: ${{ matrix.os == 'ubuntu-22.04' }}
|
||||
if: ${{ matrix.os == 'ubuntu-24.04' }}
|
||||
run: |
|
||||
sudo apt update && sudo apt install xorg-dev libsdl2-dev gcc-mingw-w64 libarchive-tools
|
||||
sudo apt update && sudo apt install xorg-dev libpng-dev libsdl2-dev g++-mingw-w64 gcc-mingw-w64 libarchive-tools mkisofs
|
||||
|
||||
- name: Install Tools (Macos)
|
||||
if: ${{ matrix.os == 'macos-15' }}
|
||||
run: |
|
||||
brew install libpng sdl2 mingw-w64 arm-none-eabi-gcc
|
||||
|
||||
brew install libpng sdl2 mingw-w64 arm-none-eabi-gcc cdrtools
|
||||
|
||||
- name: Install SDL for win32
|
||||
if: ${{ matrix.platform == 'sdl_win32' }}
|
||||
run: |
|
||||
make SDL2.dll
|
||||
|
||||
|
||||
# TODO: Don't install latest SDK, use a stable version
|
||||
- name: Install PS2DEV
|
||||
if: ${{ matrix.platform == 'ps2' }}
|
||||
run: |
|
||||
PS2DEV="$HOME/ps2dev"
|
||||
echo "PS2DEV=$HOME/ps2dev" >> "$GITHUB_ENV"
|
||||
mkdir -p $PS2DEV
|
||||
echo "PS2SDK=$PS2DEV/ps2sdk" >> "$GITHUB_ENV"
|
||||
echo "GSKIT=$PS2DEV/gsKit" >> "$GITHUB_ENV"
|
||||
echo "$PS2DEV/bin" >> "$GITHUB_PATH"
|
||||
echo "$PS2DEV/ee/bin" >> "$GITHUB_PATH"
|
||||
curl -o ps2dev-latest.tar.gz -LC - https://github.com/ps2dev/ps2dev/releases/download/latest/ps2dev-$(if [[ "$OSTYPE" == "darwin"* ]]; then echo macos; else echo ubuntu; fi)-latest.tar.gz
|
||||
tar -xf ps2dev-latest.tar.gz --strip-components 1 -C $PS2DEV
|
||||
|
||||
- name: Install PSPDEV
|
||||
if: ${{ matrix.platform == 'sdl_psp' }}
|
||||
run: |
|
||||
PSPDEV="$HOME/pspdev"
|
||||
echo "PSPDEV=$HOME/pspdev" >> "$GITHUB_ENV"
|
||||
mkdir -p $PSPDEV
|
||||
echo "$PSPDEV/bin" >> "$GITHUB_PATH"
|
||||
curl -o pspdev-latest.tar.gz -LC - https://github.com/pspdev/pspdev/releases/download/v20260301/pspdev-$(if [[ "$OSTYPE" == "darwin"* ]]; then echo "macos-latest-arm64"; else echo "ubuntu-latest-x86_64"; fi).tar.gz
|
||||
tar -xf pspdev-latest.tar.gz --strip-components 1 -C $PSPDEV
|
||||
|
||||
- name: ${{ matrix.platform }}
|
||||
run: |
|
||||
make -j${nproc} ${{ matrix.platform }}
|
||||
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
matrix:
|
||||
platform: ["sdl"]
|
||||
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}}
|
||||
runs-on: ubuntu-22.04
|
||||
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}}
|
||||
runs-on: ubuntu-24.04
|
||||
name: TAS Test ${{ matrix.platform }}
|
||||
steps:
|
||||
- name: Checkout PR
|
||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}}
|
||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}}
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
@@ -223,17 +249,17 @@ jobs:
|
||||
|
||||
- name: Install tools
|
||||
run: |
|
||||
sudo apt update && sudo apt install xorg-dev libsdl2-dev gcc-mingw-w64 libarchive-tools
|
||||
|
||||
sudo apt update && sudo apt install xorg-dev libsdl2-dev g++-mingw-w64 gcc-mingw-w64 libarchive-tools
|
||||
|
||||
- name: Install SDL for win32
|
||||
if: ${{ matrix.platform == 'sdl_win32' }}
|
||||
run: |
|
||||
make SDL2.dll
|
||||
|
||||
|
||||
- name: Build ${{ matrix.platform }}
|
||||
run: |
|
||||
make -j${nproc} ${{ matrix.platform }} TAS_TESTING=1
|
||||
|
||||
|
||||
- name: Run TAS
|
||||
timeout-minutes: 1
|
||||
env:
|
||||
@@ -242,12 +268,12 @@ jobs:
|
||||
./sa2.${{ matrix.platform }}
|
||||
|
||||
level_editor:
|
||||
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}}
|
||||
runs-on: ubuntu-22.04
|
||||
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}}
|
||||
runs-on: ubuntu-24.04
|
||||
name: Level editor (BriBaSA)
|
||||
steps:
|
||||
- name: Checkout PR
|
||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}}
|
||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}}
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
@@ -259,7 +285,7 @@ jobs:
|
||||
- name: Install deps
|
||||
run: |
|
||||
sudo apt update && sudo apt install xorg-dev libsdl2-dev
|
||||
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
make -j${nproc} bribasa
|
||||
@@ -85,6 +85,12 @@ libagbsyscall/*.s
|
||||
*.exe
|
||||
*.dll
|
||||
*.sdl
|
||||
*.iso
|
||||
|
||||
# PSP build outputs
|
||||
EBOOT.PBP
|
||||
PARAM.SFO
|
||||
sa2_debug.log
|
||||
|
||||
# third party deps
|
||||
/ext
|
||||
+28
-6
@@ -12,17 +12,29 @@ Install WSL (Ubuntu). Once installed, open this project in the WSL terminal and
|
||||
### Install system requirements
|
||||
|
||||
#### On Linux (including WSL)
|
||||
```
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install build-essential binutils-arm-none-eabi gcc-arm-none-eabi libpng-dev xorg-dev libsdl2-dev gcc-mingw-w64 libarchive-tools
|
||||
```
|
||||
sudo apt install build-essential binutils-arm-none-eabi gcc-arm-none-eabi libpng-dev xorg-dev libsdl2-dev g++-mingw-w64 gcc-mingw-w64 libarchive-tools
|
||||
|
||||
# Optional, if you want to compile for the PS2 you'll need
|
||||
sudo apt install mkisofs
|
||||
```
|
||||
#### On MacOS
|
||||
|
||||
```
|
||||
```bash
|
||||
brew install libpng sdl2 mingw-w64 arm-none-eabi-gcc
|
||||
|
||||
# Optional, if you want to compile for the PS2 you'll need
|
||||
brew install cdrtools
|
||||
```
|
||||
|
||||
#### PS2DEV and PSPDEV
|
||||
|
||||
For compiling for the PSP or PS2, ensure that you install the required SDK
|
||||
|
||||
- [PS2DEV](https://github.com/ps2dev/ps2dev)
|
||||
- [PSPDEV](https://github.com/pspdev/pspdev)
|
||||
|
||||
## Building
|
||||
|
||||
Clone/Download the repo
|
||||
@@ -33,9 +45,9 @@ Run all commands in the same folder as this project. All outputs go into the sam
|
||||
|
||||
**NOTE**: You can significantly speed up initial build times by passing the number of processes you wish to use for the build. For example `make -j4` with 4 being the number of cores
|
||||
|
||||
### PC port
|
||||
### Ports
|
||||
|
||||
The PC port targets different platforms depending on where you are going to be playing it.
|
||||
The codebase targets different platforms depending on where you are going to be playing it.
|
||||
|
||||
#### For Windows
|
||||
|
||||
@@ -54,6 +66,16 @@ Tip: On Linux and MacOS this can be opened with `wine sa2.sdl_win32.exe`
|
||||
1. `sa2.sdl` will be created
|
||||
1. Launch the game from the terminal with `./sa2.sdl`
|
||||
|
||||
#### For PSP
|
||||
|
||||
1. Run `make sdl_psp`
|
||||
1. `EBOOT.PBP` will be created
|
||||
|
||||
#### For PS2
|
||||
|
||||
1. Run `make ps2`
|
||||
1. `sa2.ps2.iso` will be created
|
||||
|
||||
### GBA rom
|
||||
|
||||
1. Clone [agbcc](https://github.com/SAT-R/agbcc) repo into another folder
|
||||
|
||||
@@ -52,6 +52,14 @@ else ifeq ($(CPU_ARCH),i386)
|
||||
TOOLCHAIN := /usr/x86_64-w64-mingw32/
|
||||
PREFIX := x86_64-w64-mingw32-
|
||||
endif
|
||||
# PSP
|
||||
else ifeq ($(PLATFORM),sdl_psp)
|
||||
PSPDEV ?= $(HOME)/pspdev
|
||||
PSPSDK := $(PSPDEV)/psp/sdk
|
||||
export PATH := $(PSPDEV)/bin:$(PATH)
|
||||
PREFIX := psp-
|
||||
else ifeq ($(PLATFORM),ps2)
|
||||
PREFIX := mips64r5900el-ps2-elf-
|
||||
else
|
||||
# Native
|
||||
ifneq ($(PLATFORM),sdl)
|
||||
@@ -74,6 +82,7 @@ CC1 := tools/agbcc/bin/agbcc$(EXE)
|
||||
CC1_OLD := tools/agbcc/bin/old_agbcc$(EXE)
|
||||
else
|
||||
CC1 := $(PREFIX)gcc$(EXE)
|
||||
CXX := $(PREFIX)g++$(EXE)
|
||||
CC1_OLD := $(CC1)
|
||||
endif
|
||||
|
||||
@@ -120,6 +129,14 @@ else ifeq ($(PLATFORM),sdl)
|
||||
ROM := $(BUILD_NAME).sdl
|
||||
ELF := $(ROM).elf
|
||||
MAP := $(ROM).map
|
||||
else ifeq ($(PLATFORM),sdl_psp)
|
||||
ROM := EBOOT.PBP
|
||||
ELF := $(BUILD_NAME).sdl_psp.elf
|
||||
MAP := $(BUILD_NAME).sdl_psp.map
|
||||
else ifeq ($(PLATFORM),ps2)
|
||||
ROM := $(BUILD_NAME).$(PLATFORM).iso
|
||||
ELF := $(ROM:.iso=.elf)
|
||||
MAP := $(ROM:.iso=.map)
|
||||
else
|
||||
ROM := $(BUILD_NAME).$(PLATFORM).exe
|
||||
ELF := $(ROM:.exe=.elf)
|
||||
@@ -156,16 +173,28 @@ TILESETS_SUBDIR = graphics/tilesets/
|
||||
ifeq ($(PLATFORM),gba)
|
||||
C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/*")
|
||||
else ifeq ($(PLATFORM),sdl)
|
||||
C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*")
|
||||
C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/ps2/*")
|
||||
else ifeq ($(PLATFORM),sdl_psp)
|
||||
C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/ps2/*")
|
||||
else ifeq ($(PLATFORM),ps2)
|
||||
C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/pret_sdl/*")
|
||||
else ifeq ($(PLATFORM),sdl_win32)
|
||||
C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*")
|
||||
C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/ps2/*")
|
||||
else ifeq ($(PLATFORM),win32)
|
||||
C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/pret_sdl/*")
|
||||
C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/pret_sdl/*" -not -path "*/platform/ps2/*")
|
||||
else
|
||||
C_SRCS := $(shell find $(C_SUBDIR) -name "*.c")
|
||||
endif
|
||||
C_OBJS := $(patsubst $(C_SUBDIR)/%.c,$(C_BUILDDIR)/%.o,$(C_SRCS))
|
||||
|
||||
ifeq ($(PLATFORM),gba)
|
||||
CXX_SRCS := $(shell find $(C_SUBDIR) -name "*.cc" -not -path "*/platform/*")
|
||||
else
|
||||
CXX_SRCS := $(shell find $(C_SUBDIR) -name "*.cc")
|
||||
endif
|
||||
|
||||
CXX_OBJS := $(patsubst $(C_SUBDIR)/%.cc,$(C_BUILDDIR)/%.o,$(CXX_SRCS))
|
||||
|
||||
# Platform not included as we only need the headers for decomp scratches
|
||||
C_HEADERS := $(shell find $(INCLUDE_DIRS) -name "*.h" -not -path "*/platform/*")
|
||||
|
||||
@@ -189,7 +218,7 @@ MID_OBJS := $(patsubst $(MID_SUBDIR)/%.mid,$(MID_BUILDDIR)/%.o,$(MID_SRCS))
|
||||
SOUND_ASM_SRCS := $(wildcard $(SOUND_ASM_SUBDIR)/*.s)
|
||||
SOUND_ASM_OBJS := $(patsubst $(SOUND_ASM_SUBDIR)/%.s,$(SOUND_ASM_BUILDDIR)/%.o,$(SOUND_ASM_SRCS))
|
||||
|
||||
OBJS := $(C_OBJS) $(ASM_OBJS) $(C_ASM_OBJS) $(DATA_ASM_OBJS) $(SONG_OBJS) $(MID_OBJS)
|
||||
OBJS := $(C_OBJS) $(CXX_OBJS) $(ASM_OBJS) $(C_ASM_OBJS) $(DATA_ASM_OBJS) $(SONG_OBJS) $(MID_OBJS)
|
||||
OBJS_REL := $(patsubst $(OBJ_DIR)/%,%,$(OBJS))
|
||||
|
||||
FORMAT_SRC_PATHS := $(shell find . -name "*.c" ! -path '*/src/data/*' ! -path '*/build/*' ! -path '*/ext/*')
|
||||
@@ -225,6 +254,12 @@ else
|
||||
ifeq ($(PLATFORM),sdl)
|
||||
CC1FLAGS += -Wno-parentheses-equality -Wno-unused-value
|
||||
CPPFLAGS += -D TITLE_BAR=$(BUILD_NAME).$(PLATFORM) -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 $(shell sdl2-config --cflags)
|
||||
else ifeq ($(PLATFORM),sdl_psp)
|
||||
CC1FLAGS += -G0
|
||||
CPPFLAGS += -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 -D SDL_MAIN_HANDLED -I$(PSPDEV)/psp/include/SDL2 -I$(PSPDEV)/psp/include -I$(PSPSDK)/include -D_PSP_FW_VERSION=600
|
||||
else ifeq ($(PLATFORM),ps2)
|
||||
CC1FLAGS += -G0 -Wno-parentheses-equality -Wno-unused-value -ffast-math
|
||||
CPPFLAGS += -D PLATFORM_GBA=0 -D PLATFORM_SDL=0 -D PLATFORM_WIN32=0 -D_EE -D__PS2__ -I$(PS2SDK)/common/include -I$(PS2SDK)/ee/include -I$(PS2DEV)/gsKit/include -I$(PS2SDK)/ports/include
|
||||
else ifeq ($(PLATFORM),sdl_win32)
|
||||
CPPFLAGS += -D TITLE_BAR=$(BUILD_NAME).$(PLATFORM) -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 $(SDL_MINGW_FLAGS)
|
||||
else ifeq ($(PLATFORM),win32)
|
||||
@@ -241,24 +276,18 @@ else
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM),gba)
|
||||
ASFLAGS += -mcpu=arm7tdmi -mthumb-interwork
|
||||
CC1FLAGS += -mthumb-interwork
|
||||
else
|
||||
ifeq ($(PLATFORM), sdl)
|
||||
# for modern we are using a modern compiler
|
||||
# so instead of CPP we can use gcc -E to "preprocess only"
|
||||
CPP := $(CC1) -E
|
||||
endif
|
||||
# Allow file input through stdin on modern GCC and set it to "compile only"
|
||||
CC1FLAGS += -x c -S
|
||||
endif
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
CC1FLAGS += -g3 -O0
|
||||
CPPFLAGS += -D DEBUG=1
|
||||
else
|
||||
CC1FLAGS += -O2
|
||||
ifeq ($(PLATFORM),sdl_psp)
|
||||
# -O3 for PSP (Allegrex MIPS, small D-cache)
|
||||
CC1FLAGS += -O3 -funroll-loops -fomit-frame-pointer
|
||||
else ifeq ($(PLATFORM),ps2)
|
||||
CC1FLAGS += -O3 -fomit-frame-pointer
|
||||
else
|
||||
CC1FLAGS += -O2
|
||||
endif
|
||||
CPPFLAGS += -D DEBUG=0
|
||||
endif
|
||||
|
||||
@@ -285,6 +314,26 @@ else
|
||||
CPPFLAGS += -D ENABLE_DECOMP_CREDITS=1
|
||||
endif
|
||||
|
||||
CXXFLAGS := $(CC1FLAGS) $(CPPFLAGS) -fno-rtti -fno-exceptions -std=c++11
|
||||
|
||||
ifeq ($(PLATFORM),gba)
|
||||
ASFLAGS += -mcpu=arm7tdmi -mthumb-interwork
|
||||
CC1FLAGS += -mthumb-interwork
|
||||
else
|
||||
ifeq ($(PLATFORM), sdl)
|
||||
# for modern we are using a modern compiler
|
||||
# so instead of CPP we can use gcc -E to "preprocess only"
|
||||
CPP := $(CC1) -E
|
||||
else ifeq ($(PLATFORM), sdl_psp)
|
||||
CPP := $(CC1) -E
|
||||
else ifeq ($(PLATFORM), ps2)
|
||||
ASFLAGS += -msingle-float
|
||||
endif
|
||||
# Allow file input through stdin on modern gcc/g++ and set it to "compile only"
|
||||
CC1FLAGS += -x c -S
|
||||
CXXFLAGS += -x c++ -S
|
||||
endif
|
||||
|
||||
### LINKER FLAGS ###
|
||||
|
||||
# GBA
|
||||
@@ -297,7 +346,7 @@ else ifeq ($(PLATFORM),sdl)
|
||||
else
|
||||
MAP_FLAG := -Xlinker -Map=
|
||||
endif
|
||||
# Win32
|
||||
# Win32, PSP, PS2
|
||||
else
|
||||
MAP_FLAG := -Xlinker -Map=
|
||||
endif
|
||||
@@ -307,6 +356,10 @@ ifeq ($(PLATFORM),gba)
|
||||
LIBS := $(ROOT_DIR)/tools/agbcc/lib/libgcc.a $(ROOT_DIR)/tools/agbcc/lib/libc.a $(LIBABGSYSCALL_LIBS)
|
||||
else ifeq ($(PLATFORM),sdl)
|
||||
LIBS := $(shell sdl2-config --cflags --libs)
|
||||
else ifeq ($(PLATFORM),sdl_psp)
|
||||
LIBS := -L$(PSPDEV)/psp/lib -L$(PSPSDK)/lib -lSDL2 -lm -lGL -lpspvram -lpspaudio -lpspvfpu -lpspdisplay -lpspgu -lpspge -lpsphprm -lpspctrl -lpsppower -lpspdebug -lpspnet -lpspnet_apctl -Wl,-zmax-page-size=128
|
||||
else ifeq ($(PLATFORM),ps2)
|
||||
LIBS := -T$(PS2SDK)/ee/startup/linkfile -L$(PS2SDK)/common/lib -L$(PS2SDK)/ee/lib -L$(PS2DEV)/gsKit/lib -L$(PS2SDK)/ports/lib -lgskit -ldmakit -lps2_drivers -lmc -lpatches -Wl,-zmax-page-size=128
|
||||
else ifeq ($(PLATFORM),sdl_win32)
|
||||
LIBS := -mwin32 -lkernel32 -lwinmm -lmingw32 -lxinput $(SDL_MINGW_LIBS)
|
||||
else ifeq ($(PLATFORM), win32)
|
||||
@@ -316,7 +369,7 @@ endif
|
||||
#### MAIN TARGETS ####
|
||||
|
||||
# these commands will run regardless of deps being completed
|
||||
.PHONY: clean tools tidy clean-tools $(TOOLDIRS) libagbsyscall
|
||||
.PHONY: clean tools tidy clean-tools $(TOOLDIRS) libagbsyscall ps2
|
||||
|
||||
# Ensure required directories exist
|
||||
$(shell mkdir -p $(C_BUILDDIR) $(ASM_BUILDDIR) $(DATA_ASM_BUILDDIR) $(SOUND_ASM_BUILDDIR) $(SONG_BUILDDIR) $(MID_BUILDDIR))
|
||||
@@ -397,7 +450,8 @@ clean-tools:
|
||||
tidy:
|
||||
$(RM) -r build/*
|
||||
$(RM) SDL2.dll
|
||||
$(RM) $(BUILD_NAME)*.exe $(BUILD_NAME)*.elf $(BUILD_NAME)*.map $(BUILD_NAME)*.sdl $(BUILD_NAME)*.gba
|
||||
$(RM) $(BUILD_NAME)*.exe $(BUILD_NAME)*.elf $(BUILD_NAME)*.map $(BUILD_NAME)*.sdl $(BUILD_NAME)*.gba $(BUILD_NAME)*.iso
|
||||
$(RM) EBOOT.PBP PARAM.SFO
|
||||
|
||||
usa_beta: ; @$(MAKE) GAME_REGION=USA GAME_VARIANT=BETA
|
||||
|
||||
@@ -409,6 +463,10 @@ europe: ; @$(MAKE) GAME_REGION=EUROPE
|
||||
|
||||
sdl: ; @$(MAKE) PLATFORM=sdl
|
||||
|
||||
sdl_psp: ; @$(MAKE) PLATFORM=sdl_psp
|
||||
|
||||
ps2: ; @$(MAKE) PLATFORM=ps2
|
||||
|
||||
tas_sdl: ; @$(MAKE) sdl TAS_TESTING=1
|
||||
|
||||
sdl_win32:
|
||||
@@ -459,7 +517,7 @@ data/mb_chao_garden_japan.gba.lz: data/mb_chao_garden_japan.gba
|
||||
|
||||
%.bin: %.aif ; $(AIF) $< $@
|
||||
|
||||
$(ELF): $(OBJS) libagbsyscall
|
||||
$(ELF): $(OBJS)
|
||||
ifeq ($(PLATFORM),gba)
|
||||
@echo "$(LD) -T $(LDSCRIPT) $(MAP_FLAG) $(MAP) <objects> <lib> -o $@"
|
||||
@$(CPP) -P $(CPPFLAGS) $(LDSCRIPT) > $(OBJ_DIR)/$(LDSCRIPT)
|
||||
@@ -470,15 +528,34 @@ else
|
||||
@cd $(OBJ_DIR) && $(CC1) $(MAP_FLAG)$(ROOT_DIR)/$(MAP) $(OBJS_REL) $(LIBS) -o $(ROOT_DIR)/$@
|
||||
endif
|
||||
|
||||
$(ROM): $(ELF)
|
||||
|
||||
ifeq ($(PLATFORM),gba)
|
||||
$(ROM): $(ELF) libagbsyscall
|
||||
$(OBJCOPY) -O binary --pad-to 0x8400000 $< $@
|
||||
$(FIX) $@ -p -t"$(TITLE)" -c$(GAME_CODE) -m$(MAKER_CODE) -r$(GAME_REVISION) --silent
|
||||
else ifeq ($(PLATFORM),sdl)
|
||||
else ifeq ($(PLATFORM),win32)
|
||||
$(ROM): $(ELF) libagbsyscall
|
||||
$(OBJCOPY) -O pei-x86-64 $< $@
|
||||
else
|
||||
$(ROM): $(ELF)
|
||||
ifeq ($(PLATFORM),sdl)
|
||||
cp $< $@
|
||||
else ifeq ($(PLATFORM),sdl_psp)
|
||||
@echo Creating $(ROM) from $(ELF)
|
||||
@psp-fixup-imports $<
|
||||
@mksfoex 'Sonic Advance 2' PARAM.SFO
|
||||
@psp-strip $< -o $(BUILD_NAME).psp_strip.elf
|
||||
@pack-pbp $@ PARAM.SFO NULL NULL NULL NULL NULL $(BUILD_NAME).psp_strip.elf NULL
|
||||
@-rm -f $(BUILD_NAME).psp_strip.elf
|
||||
else ifeq ($(PLATFORM),ps2)
|
||||
@echo Creating $(ROM) from $(ELF)
|
||||
@cp -r ps2/ntsc $(OBJ_DIR)/iso
|
||||
@cp $< $(OBJ_DIR)/iso/$(PS2_GAME_CODE)
|
||||
@mkisofs -o $(ROM) $(OBJ_DIR)/iso/
|
||||
else
|
||||
$(OBJCOPY) -O pei-x86-64 $< $@
|
||||
endif
|
||||
endif
|
||||
|
||||
# Build c sources, and ensure alignment
|
||||
$(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.c
|
||||
@@ -491,11 +568,21 @@ ifeq ($(PLATFORM), gba)
|
||||
endif
|
||||
@$(AS) $(ASFLAGS) $(C_BUILDDIR)/$*.s -o $@
|
||||
|
||||
$(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.cc
|
||||
@echo "$(CXX) <flags> -o $@ $<"
|
||||
@$(shell mkdir -p $(shell dirname '$(C_BUILDDIR)/$*.o'))
|
||||
@$(CXX) $(CXXFLAGS) -o $(C_BUILDDIR)/$*.s $<
|
||||
@$(AS) $(ASFLAGS) $(C_BUILDDIR)/$*.s -o $@
|
||||
|
||||
# Scan the src dependencies to determine if any dependent files have changed
|
||||
$(C_BUILDDIR)/%.d: $(C_SUBDIR)/%.c
|
||||
@$(shell mkdir -p $(shell dirname '$(C_BUILDDIR)/$*.d'))
|
||||
$(SCANINC) -M $@ $(INCLUDE_SCANINC_ARGS) $<
|
||||
|
||||
$(C_BUILDDIR)/%.d: $(C_SUBDIR)/%.cc
|
||||
@$(shell mkdir -p $(shell dirname '$(C_BUILDDIR)/$*.d'))
|
||||
$(SCANINC) -M $@ $(INCLUDE_SCANINC_ARGS) $<
|
||||
|
||||
# rule for sources from the src dir (parts of libraries)
|
||||
$(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.s
|
||||
@echo "$(AS) <flags> -o $@ $<"
|
||||
@@ -515,6 +602,7 @@ $(DATA_ASM_BUILDDIR)/%.d: $(DATA_ASM_SUBDIR)/%.s
|
||||
|
||||
ifneq ($(NODEP),1)
|
||||
-include $(addprefix $(OBJ_DIR)/,$(C_SRCS:.c=.d))
|
||||
-include $(addprefix $(OBJ_DIR)/,$(CXX_SRCS:.cc=.d))
|
||||
-include $(addprefix $(OBJ_DIR)/,$(DATA_ASM_SRCS:.s=.d))
|
||||
endif
|
||||
|
||||
|
||||
@@ -24,7 +24,9 @@ It builds the following ROMs:
|
||||
It can also build:
|
||||
* **sa2.sdl** `make sdl` (Linux/MacOS SDL 64bit port)
|
||||
* **sa2.sdl_win32.exe** `make sdl_win32` (Windows SDL 64bit port)
|
||||
* :construction: **sa2.win32.exe** `make win32` (Win32 native port, not functional)
|
||||
* :construction: **sa2.win32.exe** `make win32` (Win32 OpenGL port, not functional)
|
||||
* **sa2.ps2.iso** `make ps2` (PlayStation 2 port, requires [PS2DEV](https://github.com/ps2dev/ps2dev))
|
||||
* **EBOOT.PBP** `make sdl_psp` (PlayStation Portable SDL port, requires [PSPDEV](https://github.com/pspdev/pspdev))
|
||||
|
||||
## Current state
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
.macro mPtr value
|
||||
#if defined(__aarch64__) || defined(__x86_64__)
|
||||
.quad \value
|
||||
#elif defined(__mips__)
|
||||
.4byte \value
|
||||
#else
|
||||
.int \value
|
||||
#endif
|
||||
|
||||
@@ -63,6 +63,7 @@ MAKER_CODE := 78
|
||||
BUILD_NAME := sa2
|
||||
TITLE := SONICADVANC2
|
||||
GAME_CODE := A2N
|
||||
PS2_GAME_CODE := SLUS_054.02
|
||||
|
||||
|
||||
# Revision
|
||||
|
||||
@@ -42,11 +42,14 @@
|
||||
#define RENDERER_SOFTWARE 0
|
||||
#define RENDERER_OPENGL 1
|
||||
#define RENDERER_COUNT 2
|
||||
|
||||
#ifndef RENDERER
|
||||
#if PLATFORM_WIN32 && !PLATFORM_SDL
|
||||
// TODO: Only win32 for now
|
||||
#define RENDERER RENDERER_OPENGL
|
||||
#else
|
||||
#define RENDERER RENDERER_SOFTWARE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // GUARD_SA2_CONFIG_H
|
||||
@@ -39,8 +39,18 @@
|
||||
#define OAM_ENTRY_COUNT 128
|
||||
#if PORTABLE
|
||||
// NOTE: Used in gba/types.h, so they have to be defined before the #include
|
||||
#if defined(__PSP__)
|
||||
// PSP: Use GBA-native resolution, SDL scales to 480x272
|
||||
#define DISPLAY_WIDTH 240
|
||||
#define DISPLAY_HEIGHT 160
|
||||
#elif defined(__PS2__)
|
||||
// Runs at 60fps with the "fast draw"
|
||||
#define DISPLAY_WIDTH 320
|
||||
#define DISPLAY_HEIGHT 180
|
||||
#else
|
||||
#define DISPLAY_WIDTH 426
|
||||
#define DISPLAY_HEIGHT 240
|
||||
#endif
|
||||
|
||||
// NOTE: We shouldn't consider WIDESCREEN_HACK a permanent thing.
|
||||
// This hack should best be removed once there's a "native" platform layer.
|
||||
|
||||
+151
-130
@@ -5,6 +5,27 @@
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
// these are not hardware registers on ports
|
||||
// so there is no need to make re-read them
|
||||
#if PORTABLE
|
||||
typedef uint8_t reg_u8;
|
||||
typedef uint16_t reg_u16;
|
||||
typedef uint32_t reg_u32;
|
||||
typedef int16_t reg_s16;
|
||||
typedef int32_t reg_s32;
|
||||
typedef uint64_t reg_u64;
|
||||
typedef winreg_t reg_wint;
|
||||
#else
|
||||
typedef volatile uint8_t reg_u8;
|
||||
typedef volatile uint16_t reg_u16;
|
||||
typedef volatile uint32_t reg_u32;
|
||||
typedef volatile int16_t reg_s16;
|
||||
typedef volatile int32_t reg_s32;
|
||||
typedef volatile uint64_t reg_u64;
|
||||
typedef volatile winreg_t reg_wint;
|
||||
#endif
|
||||
|
||||
|
||||
#define IO_SIZE 0x400
|
||||
#if !PORTABLE
|
||||
#define REG_BASE 0x4000000 // I/O register base address
|
||||
@@ -369,155 +390,155 @@ extern unsigned char REG_BASE[IO_SIZE];
|
||||
|
||||
// I/O registers
|
||||
|
||||
#define REG_DISPCNT (*(vu16 *)REG_ADDR_DISPCNT)
|
||||
#define REG_DISPSTAT (*(vu16 *)REG_ADDR_DISPSTAT)
|
||||
#define REG_VCOUNT (*(vu16 *)REG_ADDR_VCOUNT)
|
||||
#define REG_BG0CNT (*(vu16 *)REG_ADDR_BG0CNT)
|
||||
#define REG_BG1CNT (*(vu16 *)REG_ADDR_BG1CNT)
|
||||
#define REG_BG2CNT (*(vu16 *)REG_ADDR_BG2CNT)
|
||||
#define REG_BG3CNT (*(vu16 *)REG_ADDR_BG3CNT)
|
||||
#define REG_BG0HOFS (*(vu16 *)REG_ADDR_BG0HOFS)
|
||||
#define REG_BG0VOFS (*(vu16 *)REG_ADDR_BG0VOFS)
|
||||
#define REG_BG1HOFS (*(vu16 *)REG_ADDR_BG1HOFS)
|
||||
#define REG_BG1VOFS (*(vu16 *)REG_ADDR_BG1VOFS)
|
||||
#define REG_BG2HOFS (*(vu16 *)REG_ADDR_BG2HOFS)
|
||||
#define REG_BG2VOFS (*(vu16 *)REG_ADDR_BG2VOFS)
|
||||
#define REG_BG3HOFS (*(vu16 *)REG_ADDR_BG3HOFS)
|
||||
#define REG_BG3VOFS (*(vu16 *)REG_ADDR_BG3VOFS)
|
||||
#define REG_BG2PA (*(vu16 *)REG_ADDR_BG2PA)
|
||||
#define REG_BG2PB (*(vu16 *)REG_ADDR_BG2PB)
|
||||
#define REG_BG2PC (*(vu16 *)REG_ADDR_BG2PC)
|
||||
#define REG_BG2PD (*(vu16 *)REG_ADDR_BG2PD)
|
||||
#define REG_BG2X (*(vu32 *)REG_ADDR_BG2X)
|
||||
#define REG_BG2X_L (*(vu16 *)REG_ADDR_BG2X_L)
|
||||
#define REG_BG2X_H (*(vu16 *)REG_ADDR_BG2X_H)
|
||||
#define REG_BG2Y (*(vu32 *)REG_ADDR_BG2Y)
|
||||
#define REG_BG2Y_L (*(vu16 *)REG_ADDR_BG2Y_L)
|
||||
#define REG_BG2Y_H (*(vu16 *)REG_ADDR_BG2Y_H)
|
||||
#define REG_BG3PA (*(vu16 *)REG_ADDR_BG3PA)
|
||||
#define REG_BG3PB (*(vu16 *)REG_ADDR_BG3PB)
|
||||
#define REG_BG3PC (*(vu16 *)REG_ADDR_BG3PC)
|
||||
#define REG_BG3PD (*(vu16 *)REG_ADDR_BG3PD)
|
||||
#define REG_BG3X (*(vu32 *)REG_ADDR_BG3X)
|
||||
#define REG_BG3X_L (*(vu16 *)REG_ADDR_BG3X_L)
|
||||
#define REG_BG3X_H (*(vu16 *)REG_ADDR_BG3X_H)
|
||||
#define REG_BG3Y (*(vu32 *)REG_ADDR_BG3Y)
|
||||
#define REG_BG3Y_L (*(vu16 *)REG_ADDR_BG3Y_L)
|
||||
#define REG_BG3Y_H (*(vu16 *)REG_ADDR_BG3Y_H)
|
||||
#define REG_WIN0H (*(volatile winreg_t *)REG_ADDR_WIN0H)
|
||||
#define REG_WIN1H (*(volatile winreg_t *)REG_ADDR_WIN1H)
|
||||
#define REG_WIN0V (*(volatile winreg_t *)REG_ADDR_WIN0V)
|
||||
#define REG_WIN1V (*(volatile winreg_t *)REG_ADDR_WIN1V)
|
||||
#define REG_WININ (*(volatile winreg_t *)REG_ADDR_WININ)
|
||||
#define REG_WINOUT (*(volatile winreg_t *)REG_ADDR_WINOUT)
|
||||
#define REG_MOSAIC (*(vu16 *)REG_ADDR_MOSAIC)
|
||||
#define REG_BLDCNT (*(vu16 *)REG_ADDR_BLDCNT)
|
||||
#define REG_BLDALPHA (*(vu16 *)REG_ADDR_BLDALPHA)
|
||||
#define REG_BLDY (*(vu16 *)REG_ADDR_BLDY)
|
||||
#define REG_DISPCNT (*(reg_u16 *)REG_ADDR_DISPCNT)
|
||||
#define REG_DISPSTAT (*(reg_u16 *)REG_ADDR_DISPSTAT)
|
||||
#define REG_VCOUNT (*(reg_u16 *)REG_ADDR_VCOUNT)
|
||||
#define REG_BG0CNT (*(reg_u16 *)REG_ADDR_BG0CNT)
|
||||
#define REG_BG1CNT (*(reg_u16 *)REG_ADDR_BG1CNT)
|
||||
#define REG_BG2CNT (*(reg_u16 *)REG_ADDR_BG2CNT)
|
||||
#define REG_BG3CNT (*(reg_u16 *)REG_ADDR_BG3CNT)
|
||||
#define REG_BG0HOFS (*(reg_u16 *)REG_ADDR_BG0HOFS)
|
||||
#define REG_BG0VOFS (*(reg_u16 *)REG_ADDR_BG0VOFS)
|
||||
#define REG_BG1HOFS (*(reg_u16 *)REG_ADDR_BG1HOFS)
|
||||
#define REG_BG1VOFS (*(reg_u16 *)REG_ADDR_BG1VOFS)
|
||||
#define REG_BG2HOFS (*(reg_u16 *)REG_ADDR_BG2HOFS)
|
||||
#define REG_BG2VOFS (*(reg_u16 *)REG_ADDR_BG2VOFS)
|
||||
#define REG_BG3HOFS (*(reg_u16 *)REG_ADDR_BG3HOFS)
|
||||
#define REG_BG3VOFS (*(reg_u16 *)REG_ADDR_BG3VOFS)
|
||||
#define REG_BG2PA (*(reg_u16 *)REG_ADDR_BG2PA)
|
||||
#define REG_BG2PB (*(reg_u16 *)REG_ADDR_BG2PB)
|
||||
#define REG_BG2PC (*(reg_u16 *)REG_ADDR_BG2PC)
|
||||
#define REG_BG2PD (*(reg_u16 *)REG_ADDR_BG2PD)
|
||||
#define REG_BG2X (*(reg_u32 *)REG_ADDR_BG2X)
|
||||
#define REG_BG2X_L (*(reg_u16 *)REG_ADDR_BG2X_L)
|
||||
#define REG_BG2X_H (*(reg_u16 *)REG_ADDR_BG2X_H)
|
||||
#define REG_BG2Y (*(reg_u32 *)REG_ADDR_BG2Y)
|
||||
#define REG_BG2Y_L (*(reg_u16 *)REG_ADDR_BG2Y_L)
|
||||
#define REG_BG2Y_H (*(reg_u16 *)REG_ADDR_BG2Y_H)
|
||||
#define REG_BG3PA (*(reg_u16 *)REG_ADDR_BG3PA)
|
||||
#define REG_BG3PB (*(reg_u16 *)REG_ADDR_BG3PB)
|
||||
#define REG_BG3PC (*(reg_u16 *)REG_ADDR_BG3PC)
|
||||
#define REG_BG3PD (*(reg_u16 *)REG_ADDR_BG3PD)
|
||||
#define REG_BG3X (*(reg_u32 *)REG_ADDR_BG3X)
|
||||
#define REG_BG3X_L (*(reg_u16 *)REG_ADDR_BG3X_L)
|
||||
#define REG_BG3X_H (*(reg_u16 *)REG_ADDR_BG3X_H)
|
||||
#define REG_BG3Y (*(reg_u32 *)REG_ADDR_BG3Y)
|
||||
#define REG_BG3Y_L (*(reg_u16 *)REG_ADDR_BG3Y_L)
|
||||
#define REG_BG3Y_H (*(reg_u16 *)REG_ADDR_BG3Y_H)
|
||||
#define REG_WIN0H (*(reg_wint *)REG_ADDR_WIN0H)
|
||||
#define REG_WIN1H (*(reg_wint *)REG_ADDR_WIN1H)
|
||||
#define REG_WIN0V (*(reg_wint *)REG_ADDR_WIN0V)
|
||||
#define REG_WIN1V (*(reg_wint *)REG_ADDR_WIN1V)
|
||||
#define REG_WININ (*(reg_wint *)REG_ADDR_WININ)
|
||||
#define REG_WINOUT (*(reg_wint *)REG_ADDR_WINOUT)
|
||||
#define REG_MOSAIC (*(reg_u16 *)REG_ADDR_MOSAIC)
|
||||
#define REG_BLDCNT (*(reg_u16 *)REG_ADDR_BLDCNT)
|
||||
#define REG_BLDALPHA (*(reg_u16 *)REG_ADDR_BLDALPHA)
|
||||
#define REG_BLDY (*(reg_u16 *)REG_ADDR_BLDY)
|
||||
|
||||
#define REG_SOUND1CNT_L (*(vu16 *)REG_ADDR_SOUND1CNT_L)
|
||||
#define REG_NR10 (*(vu8 *)REG_ADDR_NR10)
|
||||
#define REG_SOUND1CNT_H (*(vu16 *)REG_ADDR_SOUND1CNT_H)
|
||||
#define REG_NR11 (*(vu8 *)REG_ADDR_NR11)
|
||||
#define REG_NR12 (*(vu8 *)REG_ADDR_NR12)
|
||||
#define REG_SOUND1CNT_X (*(vu16 *)REG_ADDR_SOUND1CNT_X)
|
||||
#define REG_NR13 (*(vu8 *)REG_ADDR_NR13)
|
||||
#define REG_NR14 (*(vu8 *)REG_ADDR_NR14)
|
||||
#define REG_SOUND2CNT_L (*(vu16 *)REG_ADDR_SOUND2CNT_L)
|
||||
#define REG_NR21 (*(vu8 *)REG_ADDR_NR21)
|
||||
#define REG_NR22 (*(vu8 *)REG_ADDR_NR22)
|
||||
#define REG_SOUND2CNT_H (*(vu16 *)REG_ADDR_SOUND2CNT_H)
|
||||
#define REG_NR23 (*(vu8 *)REG_ADDR_NR23)
|
||||
#define REG_NR24 (*(vu8 *)REG_ADDR_NR24)
|
||||
#define REG_SOUND3CNT_L (*(vu16 *)REG_ADDR_SOUND3CNT_L)
|
||||
#define REG_NR30 (*(vu8 *)REG_ADDR_NR30)
|
||||
#define REG_SOUND3CNT_H (*(vu16 *)REG_ADDR_SOUND3CNT_H)
|
||||
#define REG_NR31 (*(vu8 *)REG_ADDR_NR31)
|
||||
#define REG_NR32 (*(vu8 *)REG_ADDR_NR32)
|
||||
#define REG_SOUND3CNT_X (*(vu16 *)REG_ADDR_SOUND3CNT_X)
|
||||
#define REG_NR33 (*(vu8 *)REG_ADDR_NR33)
|
||||
#define REG_NR34 (*(vu8 *)REG_ADDR_NR34)
|
||||
#define REG_SOUND4CNT_L (*(vu16 *)REG_ADDR_SOUND4CNT_L)
|
||||
#define REG_NR41 (*(vu8 *)REG_ADDR_NR41)
|
||||
#define REG_NR42 (*(vu8 *)REG_ADDR_NR42)
|
||||
#define REG_SOUND4CNT_H (*(vu16 *)REG_ADDR_SOUND4CNT_H)
|
||||
#define REG_NR43 (*(vu8 *)REG_ADDR_NR43)
|
||||
#define REG_NR44 (*(vu8 *)REG_ADDR_NR44)
|
||||
#define REG_SOUNDCNT_L (*(vu16 *)REG_ADDR_SOUNDCNT_L)
|
||||
#define REG_NR50 (*(vu8 *)REG_ADDR_NR50)
|
||||
#define REG_NR51 (*(vu8 *)REG_ADDR_NR51)
|
||||
#define REG_SOUNDCNT_H (*(vu16 *)REG_ADDR_SOUNDCNT_H)
|
||||
#define REG_SOUNDCNT_X (*(vu16 *)REG_ADDR_SOUNDCNT_X)
|
||||
#define REG_NR52 (*(vu8 *)REG_ADDR_NR52)
|
||||
#define REG_SOUNDBIAS (*(vu16 *)REG_ADDR_SOUNDBIAS)
|
||||
#define REG_SOUNDBIAS_L (*(vu8 *)REG_ADDR_SOUNDBIAS_L)
|
||||
#define REG_SOUNDBIAS_H (*(vu8 *)REG_ADDR_SOUNDBIAS_H)
|
||||
#define REG_WAVE_RAM0 (*(vu32 *)REG_ADDR_WAVE_RAM0)
|
||||
#define REG_WAVE_RAM1 (*(vu32 *)REG_ADDR_WAVE_RAM1)
|
||||
#define REG_WAVE_RAM2 (*(vu32 *)REG_ADDR_WAVE_RAM2)
|
||||
#define REG_WAVE_RAM3 (*(vu32 *)REG_ADDR_WAVE_RAM3)
|
||||
#define REG_FIFO_A (*(vu32 *)REG_ADDR_FIFO_A)
|
||||
#define REG_FIFO_B (*(vu32 *)REG_ADDR_FIFO_B)
|
||||
#define REG_SOUND1CNT_L (*(reg_u16 *)REG_ADDR_SOUND1CNT_L)
|
||||
#define REG_NR10 (*(reg_u8 *)REG_ADDR_NR10)
|
||||
#define REG_SOUND1CNT_H (*(reg_u16 *)REG_ADDR_SOUND1CNT_H)
|
||||
#define REG_NR11 (*(reg_u8 *)REG_ADDR_NR11)
|
||||
#define REG_NR12 (*(reg_u8 *)REG_ADDR_NR12)
|
||||
#define REG_SOUND1CNT_X (*(reg_u16 *)REG_ADDR_SOUND1CNT_X)
|
||||
#define REG_NR13 (*(reg_u8 *)REG_ADDR_NR13)
|
||||
#define REG_NR14 (*(reg_u8 *)REG_ADDR_NR14)
|
||||
#define REG_SOUND2CNT_L (*(reg_u16 *)REG_ADDR_SOUND2CNT_L)
|
||||
#define REG_NR21 (*(reg_u8 *)REG_ADDR_NR21)
|
||||
#define REG_NR22 (*(reg_u8 *)REG_ADDR_NR22)
|
||||
#define REG_SOUND2CNT_H (*(reg_u16 *)REG_ADDR_SOUND2CNT_H)
|
||||
#define REG_NR23 (*(reg_u8 *)REG_ADDR_NR23)
|
||||
#define REG_NR24 (*(reg_u8 *)REG_ADDR_NR24)
|
||||
#define REG_SOUND3CNT_L (*(reg_u16 *)REG_ADDR_SOUND3CNT_L)
|
||||
#define REG_NR30 (*(reg_u8 *)REG_ADDR_NR30)
|
||||
#define REG_SOUND3CNT_H (*(reg_u16 *)REG_ADDR_SOUND3CNT_H)
|
||||
#define REG_NR31 (*(reg_u8 *)REG_ADDR_NR31)
|
||||
#define REG_NR32 (*(reg_u8 *)REG_ADDR_NR32)
|
||||
#define REG_SOUND3CNT_X (*(reg_u16 *)REG_ADDR_SOUND3CNT_X)
|
||||
#define REG_NR33 (*(reg_u8 *)REG_ADDR_NR33)
|
||||
#define REG_NR34 (*(reg_u8 *)REG_ADDR_NR34)
|
||||
#define REG_SOUND4CNT_L (*(reg_u16 *)REG_ADDR_SOUND4CNT_L)
|
||||
#define REG_NR41 (*(reg_u8 *)REG_ADDR_NR41)
|
||||
#define REG_NR42 (*(reg_u8 *)REG_ADDR_NR42)
|
||||
#define REG_SOUND4CNT_H (*(reg_u16 *)REG_ADDR_SOUND4CNT_H)
|
||||
#define REG_NR43 (*(reg_u8 *)REG_ADDR_NR43)
|
||||
#define REG_NR44 (*(reg_u8 *)REG_ADDR_NR44)
|
||||
#define REG_SOUNDCNT_L (*(reg_u16 *)REG_ADDR_SOUNDCNT_L)
|
||||
#define REG_NR50 (*(reg_u8 *)REG_ADDR_NR50)
|
||||
#define REG_NR51 (*(reg_u8 *)REG_ADDR_NR51)
|
||||
#define REG_SOUNDCNT_H (*(reg_u16 *)REG_ADDR_SOUNDCNT_H)
|
||||
#define REG_SOUNDCNT_X (*(reg_u16 *)REG_ADDR_SOUNDCNT_X)
|
||||
#define REG_NR52 (*(reg_u8 *)REG_ADDR_NR52)
|
||||
#define REG_SOUNDBIAS (*(reg_u16 *)REG_ADDR_SOUNDBIAS)
|
||||
#define REG_SOUNDBIAS_L (*(reg_u8 *)REG_ADDR_SOUNDBIAS_L)
|
||||
#define REG_SOUNDBIAS_H (*(reg_u8 *)REG_ADDR_SOUNDBIAS_H)
|
||||
#define REG_WAVE_RAM0 (*(reg_u32 *)REG_ADDR_WAVE_RAM0)
|
||||
#define REG_WAVE_RAM1 (*(reg_u32 *)REG_ADDR_WAVE_RAM1)
|
||||
#define REG_WAVE_RAM2 (*(reg_u32 *)REG_ADDR_WAVE_RAM2)
|
||||
#define REG_WAVE_RAM3 (*(reg_u32 *)REG_ADDR_WAVE_RAM3)
|
||||
#define REG_FIFO_A (*(reg_u32 *)REG_ADDR_FIFO_A)
|
||||
#define REG_FIFO_B (*(reg_u32 *)REG_ADDR_FIFO_B)
|
||||
|
||||
#define REG_DMA0SAD (*(volatile uintptr_t *)REG_ADDR_DMA0SAD)
|
||||
#define REG_DMA0DAD (*(volatile uintptr_t *)REG_ADDR_DMA0DAD)
|
||||
#define REG_DMA0CNT (*(vu32 *)REG_ADDR_DMA0CNT)
|
||||
#define REG_DMA0CNT_L (*(vu16 *)REG_ADDR_DMA0CNT_L)
|
||||
#define REG_DMA0CNT_H (*(vu16 *)REG_ADDR_DMA0CNT_H)
|
||||
#define REG_DMA0CNT (*(reg_u32 *)REG_ADDR_DMA0CNT)
|
||||
#define REG_DMA0CNT_L (*(reg_u16 *)REG_ADDR_DMA0CNT_L)
|
||||
#define REG_DMA0CNT_H (*(reg_u16 *)REG_ADDR_DMA0CNT_H)
|
||||
|
||||
#define REG_DMA1SAD (*(volatile uintptr_t *)REG_ADDR_DMA1SAD)
|
||||
#define REG_DMA1DAD (*(volatile uintptr_t *)REG_ADDR_DMA1DAD)
|
||||
#define REG_DMA1CNT (*(vu32 *)REG_ADDR_DMA1CNT)
|
||||
#define REG_DMA1CNT_L (*(vu16 *)REG_ADDR_DMA1CNT_L)
|
||||
#define REG_DMA1CNT_H (*(vu16 *)REG_ADDR_DMA1CNT_H)
|
||||
#define REG_DMA1CNT (*(reg_u32 *)REG_ADDR_DMA1CNT)
|
||||
#define REG_DMA1CNT_L (*(reg_u16 *)REG_ADDR_DMA1CNT_L)
|
||||
#define REG_DMA1CNT_H (*(reg_u16 *)REG_ADDR_DMA1CNT_H)
|
||||
|
||||
#define REG_DMA2SAD (*(volatile uintptr_t *)REG_ADDR_DMA2SAD)
|
||||
#define REG_DMA2DAD (*(volatile uintptr_t *)REG_ADDR_DMA2DAD)
|
||||
#define REG_DMA2CNT (*(vu32 *)REG_ADDR_DMA2CNT)
|
||||
#define REG_DMA2CNT_L (*(vu16 *)REG_ADDR_DMA2CNT_L)
|
||||
#define REG_DMA2CNT_H (*(vu16 *)REG_ADDR_DMA2CNT_H)
|
||||
#define REG_DMA2CNT (*(reg_u32 *)REG_ADDR_DMA2CNT)
|
||||
#define REG_DMA2CNT_L (*(reg_u16 *)REG_ADDR_DMA2CNT_L)
|
||||
#define REG_DMA2CNT_H (*(reg_u16 *)REG_ADDR_DMA2CNT_H)
|
||||
|
||||
#define REG_DMA3SAD (*(volatile uintptr_t *)REG_ADDR_DMA3SAD)
|
||||
#define REG_DMA3DAD (*(volatile uintptr_t *)REG_ADDR_DMA3DAD)
|
||||
#define REG_DMA3CNT (*(vu32 *)REG_ADDR_DMA3CNT)
|
||||
#define REG_DMA3CNT_L (*(vu16 *)REG_ADDR_DMA3CNT_L)
|
||||
#define REG_DMA3CNT_H (*(vu16 *)REG_ADDR_DMA3CNT_H)
|
||||
#define REG_DMA3CNT (*(reg_u32 *)REG_ADDR_DMA3CNT)
|
||||
#define REG_DMA3CNT_L (*(reg_u16 *)REG_ADDR_DMA3CNT_L)
|
||||
#define REG_DMA3CNT_H (*(reg_u16 *)REG_ADDR_DMA3CNT_H)
|
||||
|
||||
#define REG_TMCNT(n) (*(vu16 *)(REG_ADDR_TMCNT + ((n) * 4)))
|
||||
#define REG_TM0CNT (*(vu32 *)REG_ADDR_TM0CNT)
|
||||
#define REG_TM0CNT_L (*(vu16 *)REG_ADDR_TM0CNT_L)
|
||||
#define REG_TM0CNT_H (*(vu16 *)REG_ADDR_TM0CNT_H)
|
||||
#define REG_TM1CNT (*(vu32 *)REG_ADDR_TM1CNT)
|
||||
#define REG_TM1CNT_L (*(vu16 *)REG_ADDR_TM1CNT_L)
|
||||
#define REG_TM1CNT_H (*(vu16 *)REG_ADDR_TM1CNT_H)
|
||||
#define REG_TM2CNT (*(vu32 *)REG_ADDR_TM2CNT)
|
||||
#define REG_TM2CNT_L (*(vu16 *)REG_ADDR_TM2CNT_L)
|
||||
#define REG_TM2CNT_H (*(vu16 *)REG_ADDR_TM2CNT_H)
|
||||
#define REG_TM3CNT (*(vu32 *)REG_ADDR_TM3CNT)
|
||||
#define REG_TM3CNT_L (*(vu16 *)REG_ADDR_TM3CNT_L)
|
||||
#define REG_TM3CNT_H (*(vu16 *)REG_ADDR_TM3CNT_H)
|
||||
#define REG_TMCNT(n) (*(reg_u16 *)(REG_ADDR_TMCNT + ((n) * 4)))
|
||||
#define REG_TM0CNT (*(reg_u32 *)REG_ADDR_TM0CNT)
|
||||
#define REG_TM0CNT_L (*(reg_u16 *)REG_ADDR_TM0CNT_L)
|
||||
#define REG_TM0CNT_H (*(reg_u16 *)REG_ADDR_TM0CNT_H)
|
||||
#define REG_TM1CNT (*(reg_u32 *)REG_ADDR_TM1CNT)
|
||||
#define REG_TM1CNT_L (*(reg_u16 *)REG_ADDR_TM1CNT_L)
|
||||
#define REG_TM1CNT_H (*(reg_u16 *)REG_ADDR_TM1CNT_H)
|
||||
#define REG_TM2CNT (*(reg_u32 *)REG_ADDR_TM2CNT)
|
||||
#define REG_TM2CNT_L (*(reg_u16 *)REG_ADDR_TM2CNT_L)
|
||||
#define REG_TM2CNT_H (*(reg_u16 *)REG_ADDR_TM2CNT_H)
|
||||
#define REG_TM3CNT (*(reg_u32 *)REG_ADDR_TM3CNT)
|
||||
#define REG_TM3CNT_L (*(reg_u16 *)REG_ADDR_TM3CNT_L)
|
||||
#define REG_TM3CNT_H (*(reg_u16 *)REG_ADDR_TM3CNT_H)
|
||||
|
||||
#define REG_SIOCNT (*(vu16 *)REG_ADDR_SIOCNT)
|
||||
#define REG_SIOCNT_32 (*(vu32 *)REG_ADDR_SIOCNT)
|
||||
#define REG_SIODATA8 (*(vu16 *)REG_ADDR_SIODATA8)
|
||||
#define REG_SIODATA32 (*(vu32 *)REG_ADDR_SIODATA32)
|
||||
#define REG_SIOMLT_SEND (*(vu16 *)REG_ADDR_SIOMLT_SEND)
|
||||
#define REG_SIOMLT_RECV (*(vu64 *)REG_ADDR_SIOMLT_RECV)
|
||||
#define REG_SIOMULTI0 (*(vu16 *)REG_ADDR_SIOMULTI0)
|
||||
#define REG_SIOMULTI1 (*(vu16 *)REG_ADDR_SIOMULTI1)
|
||||
#define REG_SIOMULTI2 (*(vu16 *)REG_ADDR_SIOMULTI2)
|
||||
#define REG_SIOMULTI3 (*(vu16 *)REG_ADDR_SIOMULTI3)
|
||||
#define REG_SIOCNT (*(reg_u16 *)REG_ADDR_SIOCNT)
|
||||
#define REG_SIOCNT_32 (*(reg_u32 *)REG_ADDR_SIOCNT)
|
||||
#define REG_SIODATA8 (*(reg_u16 *)REG_ADDR_SIODATA8)
|
||||
#define REG_SIODATA32 (*(reg_u32 *)REG_ADDR_SIODATA32)
|
||||
#define REG_SIOMLT_SEND (*(reg_u16 *)REG_ADDR_SIOMLT_SEND)
|
||||
#define REG_SIOMLT_RECV (*(reg_u64 *)REG_ADDR_SIOMLT_RECV)
|
||||
#define REG_SIOMULTI0 (*(reg_u16 *)REG_ADDR_SIOMULTI0)
|
||||
#define REG_SIOMULTI1 (*(reg_u16 *)REG_ADDR_SIOMULTI1)
|
||||
#define REG_SIOMULTI2 (*(reg_u16 *)REG_ADDR_SIOMULTI2)
|
||||
#define REG_SIOMULTI3 (*(reg_u16 *)REG_ADDR_SIOMULTI3)
|
||||
|
||||
#define REG_KEYINPUT (*(vu16 *)REG_ADDR_KEYINPUT)
|
||||
#define REG_KEYCNT (*(vu16 *)REG_ADDR_KEYCNT)
|
||||
#define REG_KEYINPUT (*(reg_u16 *)REG_ADDR_KEYINPUT)
|
||||
#define REG_KEYCNT (*(reg_u16 *)REG_ADDR_KEYCNT)
|
||||
|
||||
#define REG_RCNT (*(vu16 *)REG_ADDR_RCNT)
|
||||
#define REG_RCNT (*(reg_u16 *)REG_ADDR_RCNT)
|
||||
|
||||
#define REG_IME (*(vu16 *)REG_ADDR_IME)
|
||||
#define REG_IE (*(vu16 *)REG_ADDR_IE)
|
||||
#define REG_IF (*(vu16 *)REG_ADDR_IF)
|
||||
#define REG_IME (*(reg_u16 *)REG_ADDR_IME)
|
||||
#define REG_IE (*(reg_u16 *)REG_ADDR_IE)
|
||||
#define REG_IF (*(reg_u16 *)REG_ADDR_IF)
|
||||
|
||||
#define REG_WAITCNT (*(vu16 *)REG_ADDR_WAITCNT)
|
||||
#define REG_WAITCNT (*(reg_u16 *)REG_ADDR_WAITCNT)
|
||||
|
||||
// I/O register fields
|
||||
|
||||
|
||||
+7
-3
@@ -20,6 +20,9 @@
|
||||
typedef struct __attribute__((packed)) name struct_body name;
|
||||
#endif
|
||||
|
||||
#ifdef __PS2__
|
||||
#include <tamtypes.h>
|
||||
#else
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
@@ -28,6 +31,7 @@ typedef int8_t s8;
|
||||
typedef int16_t s16;
|
||||
typedef int32_t s32;
|
||||
typedef int64_t s64;
|
||||
#endif
|
||||
|
||||
#if (GAME == GAME_SA1)
|
||||
typedef u8 MetatileIndexType;
|
||||
@@ -38,12 +42,12 @@ typedef u16 MetatileIndexType;
|
||||
// If the DISPLAY_HEIGHT was >255, scanline effects would break,
|
||||
// so we have to make this variable bigger.
|
||||
// (u16 should be plenty for screen coordinates, right?)
|
||||
#if !defined(DISPLAY_HEIGHT)
|
||||
#error DISPLAY_HEIGHT not defined.
|
||||
#if !defined(WIDESCREEN_HACK) && !PLATFORM_GBA
|
||||
#error WIDESCREEN_HACK not defined.
|
||||
#endif
|
||||
/// TODO: Technically this should only be #if (DISPLAY_HEIGHT > 255),
|
||||
// we should probably replace uses of int_vcount with a different type where a high DISPLAY_WIDTH necessitates u16.
|
||||
#if ((DISPLAY_WIDTH > 255) || (DISPLAY_HEIGHT > 255))
|
||||
#if !PLATFORM_GBA && WIDESCREEN_HACK
|
||||
typedef u16 int_vcount;
|
||||
#else
|
||||
typedef u8 int_vcount;
|
||||
|
||||
@@ -106,6 +106,13 @@
|
||||
#define MAX_LINES 0
|
||||
#endif
|
||||
|
||||
typedef s32 fixed8_24;
|
||||
#define float_to_fp8_24(value) (fixed8_24)((value)*16777216.0f)
|
||||
#define u32_to_fp8_24(value) ((value) << 24)
|
||||
#define fp8_24_to_u32(value) ((value) >> 24)
|
||||
#define fp8_24_to_float(value) (float)((value) / 16777216.0f)
|
||||
#define fp8_24_fractional_part(value) ((value)&0xFFFFFF)
|
||||
|
||||
struct MP2KTrack;
|
||||
struct MP2KPlayerState;
|
||||
|
||||
@@ -185,7 +192,7 @@ struct MixerSource {
|
||||
u8 padding5;
|
||||
|
||||
u32 ct;
|
||||
float fw;
|
||||
fixed8_24 fw;
|
||||
|
||||
u32 freq;
|
||||
} sound;
|
||||
@@ -243,7 +250,7 @@ struct SoundMixerState {
|
||||
#if PLATFORM_GBA
|
||||
s8 pcmBuffer[PCM_DMA_BUF_SIZE * 2];
|
||||
#else
|
||||
float pcmBuffer[PCM_DMA_BUF_SIZE * 2];
|
||||
fixed8_24 pcmBuffer[PCM_DMA_BUF_SIZE * 2];
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ extern void Platform_RLFree(unsigned char *dest);
|
||||
extern void Platform_LZDecompressUnsafe(unsigned char *src, unsigned char *dest);
|
||||
extern void Platform_RLDecompressUnsafe(unsigned char *src, unsigned char *dest);
|
||||
|
||||
extern void Platform_QueueAudio(const void *data, u32 numBytes);
|
||||
extern void Platform_QueueAudio(const s16 *data, u32 numBytes);
|
||||
extern void Platform_ProcessBackgroundsCopyQueue(void);
|
||||
// TODO: Re-enable once #include-ing global.h/core.h/sprite.h does not result in compilation errors.
|
||||
// void Platform_TransformSprite(Sprite *s, SpriteTransform *transform);
|
||||
|
||||
@@ -18,9 +18,9 @@ struct AudioCGB {
|
||||
u8 EnvCounterI[4];
|
||||
bool8 EnvDir[4];
|
||||
bool8 DAC[4];
|
||||
float WAVRAM[32];
|
||||
fixed8_24 WAVRAM[32];
|
||||
u16 ch4LFSR[2];
|
||||
float outBuffer[PCM_DMA_BUF_SIZE * 2];
|
||||
fixed8_24 outBuffer[PCM_DMA_BUF_SIZE * 2];
|
||||
};
|
||||
|
||||
void cgb_audio_init(u32 rate);
|
||||
@@ -31,6 +31,6 @@ void cgb_set_length(u8 channel, u8 length);
|
||||
void cgb_set_envelope(u8 channel, u8 envelope);
|
||||
void cgb_trigger_note(u8 channel);
|
||||
void cgb_audio_generate(u16 samplesPerFrame);
|
||||
float *cgb_get_buffer();
|
||||
fixed8_24 *cgb_get_buffer();
|
||||
|
||||
#endif
|
||||
+2348
-2087
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
|
||||
@@ -0,0 +1,3 @@
|
||||
BOOT2 = cdrom0:\SLUS_054.02;1
|
||||
VER = 1.00
|
||||
VMODE = NTSC
|
||||
@@ -106,6 +106,9 @@ void GameInit(void)
|
||||
// GameStageStart();
|
||||
|
||||
#elif ENABLE_DECOMP_CREDITS
|
||||
// gCurrentLevel = LEVEL_INDEX(ZONE_4, ACT_1);
|
||||
// ApplyGameStageSettings();
|
||||
// GameStageStart();
|
||||
CreateDecompCreditsScreen(hasProfile);
|
||||
#else
|
||||
if (gFlags & FLAGS_NO_FLASH_MEMORY) {
|
||||
|
||||
@@ -238,19 +238,10 @@ void sub_806EA04(void)
|
||||
temp5 = (i - stage->cameraHeight) * temp2 * 2;
|
||||
|
||||
*unk1884++ = (Q_16_16_TO_INT(temp) * cos) >> 0x10; // BG2PA
|
||||
// HACK: in SDL we don't handle these PB and PD values properly
|
||||
#if PLATFORM_SDL
|
||||
*unk1884++ = 0;
|
||||
#else
|
||||
*unk1884++ = (Q_16_16_TO_INT(temp) * sin) >> 0x10; // BG2PB
|
||||
#endif
|
||||
|
||||
*unk1884++ = (Q_16_16_TO_INT(temp) * -sin) >> 0x10; // BG2PC
|
||||
#if PLATFORM_SDL
|
||||
*unk1884++ = 0;
|
||||
#else
|
||||
*unk1884++ = (Q_16_16_TO_INT(temp) * cos) >> 0x10; // BG2PD
|
||||
#endif
|
||||
|
||||
x = (Q_16_16_TO_INT(temp5) * sin) + (Q_16_16_TO_INT(temp4) * cos) + stage->q16CameraX;
|
||||
y = (Q_16_16_TO_INT(temp4) * -sin) + (Q_16_16_TO_INT(temp5) * cos) + stage->q16CameraY;
|
||||
|
||||
@@ -941,7 +941,7 @@ NONMATCH("asm/non_matching/game/stage/background/StageBgUpdate_Zone2Acts12.inc",
|
||||
|
||||
gFlags |= FLAGS_EXECUTE_HBLANK_COPY;
|
||||
gHBlankCopyTarget = (void *)REG_ADDR_BG3HOFS;
|
||||
gHBlankCopySize = 4;
|
||||
gHBlankCopySize = sizeof(u16) * 2;
|
||||
|
||||
cursor = gBgOffsetsHBlankPrimary;
|
||||
dt = gStageTime * 0x18;
|
||||
@@ -1202,9 +1202,13 @@ void CreateStageBg_Zone4(void)
|
||||
gBgScrollRegs[3][0] = 0;
|
||||
gBgScrollRegs[3][1] = 0;
|
||||
|
||||
// Software renderer for these devices are too slow
|
||||
// to handle these spotlights
|
||||
#if !defined(__PS2__) && !defined(__PSP__)
|
||||
if (IS_SINGLE_PLAYER) {
|
||||
CreateSpotLightBeams();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void StageBgUpdate_Zone4Acts12(s32 cameraX, s32 cameraY)
|
||||
|
||||
+177
-948
File diff suppressed because it is too large.
Load diff
@@ -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; }
|
||||
@@ -3,14 +3,16 @@
|
||||
#include "platform/shared/audio/cgb_tables.h"
|
||||
|
||||
static struct AudioCGB gb;
|
||||
static float soundChannelPos[4];
|
||||
static const s16 *PU1Table;
|
||||
static const s16 *PU2Table;
|
||||
static fixed8_24 soundChannelPos[4];
|
||||
static const fixed8_24 *PU1Table;
|
||||
static const fixed8_24 *PU2Table;
|
||||
static u32 apuFrame;
|
||||
static u8 apuCycle;
|
||||
static u32 sampleRate;
|
||||
static u16 lfsrMax[2];
|
||||
float ch4Samples;
|
||||
fixed8_24 ch4Samples;
|
||||
fixed8_24 volScale[16];
|
||||
fixed8_24 ch4StepsScale[12];
|
||||
|
||||
void cgb_audio_init(u32 rate)
|
||||
{
|
||||
@@ -31,7 +33,7 @@ void cgb_audio_init(u32 rate)
|
||||
gb.DAC[ch] = 0;
|
||||
soundChannelPos[ch] = 0;
|
||||
}
|
||||
soundChannelPos[1] = 1;
|
||||
soundChannelPos[1] = u32_to_fp8_24(1);
|
||||
PU1Table = PU0;
|
||||
PU2Table = PU0;
|
||||
sampleRate = rate;
|
||||
@@ -39,7 +41,12 @@ void cgb_audio_init(u32 rate)
|
||||
gb.ch4LFSR[1] = 0x80;
|
||||
lfsrMax[0] = 0x8000;
|
||||
lfsrMax[1] = 0x80;
|
||||
ch4Samples = 0.0f;
|
||||
ch4Samples = 0;
|
||||
for (int i = 0; i < 16; i++)
|
||||
volScale[i] = u32_to_fp8_24(i) / 15;
|
||||
|
||||
for (int i = 0; i < 12; i++)
|
||||
ch4StepsScale[i] = u32_to_fp8_24(1) / (i + 1);
|
||||
}
|
||||
|
||||
void cgb_set_sweep(u8 sweep)
|
||||
@@ -52,8 +59,8 @@ void cgb_set_sweep(u8 sweep)
|
||||
void cgb_set_wavram()
|
||||
{
|
||||
for (u8 wavi = 0; wavi < 0x10; wavi++) {
|
||||
gb.WAVRAM[(wavi << 1)] = (((*(REG_ADDR_WAVE_RAM0 + wavi)) & 0xF0) >> 4) / 7.5f - 1.0f;
|
||||
gb.WAVRAM[(wavi << 1) + 1] = (((*(REG_ADDR_WAVE_RAM0 + wavi)) & 0x0F)) / 7.5f - 1.0f;
|
||||
gb.WAVRAM[(wavi << 1)] = (u32_to_fp8_24(((*(REG_ADDR_WAVE_RAM0 + wavi)) & 0xF0) >> 4) * 2) / 15 - u32_to_fp8_24(1);
|
||||
gb.WAVRAM[(wavi << 1) + 1] = (u32_to_fp8_24(((*(REG_ADDR_WAVE_RAM0 + wavi)) & 0x0F)) * 2) / 15 - u32_to_fp8_24(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +110,7 @@ void cgb_trigger_note(u8 channel)
|
||||
|
||||
void cgb_audio_generate(u16 samplesPerFrame)
|
||||
{
|
||||
float *outBuffer = gb.outBuffer;
|
||||
fixed8_24 *outBuffer = gb.outBuffer;
|
||||
switch (REG_NR11 & 0xC0) {
|
||||
case 0x00:
|
||||
PU1Table = PU0;
|
||||
@@ -193,75 +200,80 @@ void cgb_audio_generate(u16 samplesPerFrame)
|
||||
}
|
||||
}
|
||||
// Sound generation loop
|
||||
soundChannelPos[0] += freqTable[REG_SOUND1CNT_X & 0x7FF] / (sampleRate / 32);
|
||||
soundChannelPos[1] += freqTable[REG_SOUND2CNT_H & 0x7FF] / (sampleRate / 32);
|
||||
soundChannelPos[2] += freqTable[REG_SOUND3CNT_X & 0x7FF] / (sampleRate / 32);
|
||||
while (soundChannelPos[0] >= 32)
|
||||
soundChannelPos[0] -= 32;
|
||||
while (soundChannelPos[1] >= 32)
|
||||
soundChannelPos[1] -= 32;
|
||||
while (soundChannelPos[2] >= 32)
|
||||
soundChannelPos[2] -= 32;
|
||||
float outputL = 0;
|
||||
float outputR = 0;
|
||||
soundChannelPos[0] += freqTable[REG_SOUND1CNT_X & (ARRAY_COUNT(freqTable) - 1)];
|
||||
soundChannelPos[1] += freqTable[REG_SOUND2CNT_H & (ARRAY_COUNT(freqTable) - 1)];
|
||||
soundChannelPos[2] += freqTable[REG_SOUND3CNT_X & (ARRAY_COUNT(freqTable) - 1)];
|
||||
|
||||
soundChannelPos[0] &= (u32_to_fp8_24(32)) - 1;
|
||||
soundChannelPos[1] &= (u32_to_fp8_24(32)) - 1;
|
||||
soundChannelPos[2] &= (u32_to_fp8_24(32)) - 1;
|
||||
|
||||
fixed8_24 outputL = 0;
|
||||
fixed8_24 outputR = 0;
|
||||
if (REG_NR52 & 0x80) {
|
||||
if ((gb.DAC[0]) && (REG_NR52 & 0x01)) {
|
||||
if (REG_NR51 & 0x10)
|
||||
outputL += gb.Vol[0] * PU1Table[(int)(soundChannelPos[0])] / 15.0f;
|
||||
outputL += (gb.Vol[0] * PU1Table[fp8_24_to_u32(soundChannelPos[0])]);
|
||||
if (REG_NR51 & 0x01)
|
||||
outputR += gb.Vol[0] * PU1Table[(int)(soundChannelPos[0])] / 15.0f;
|
||||
outputR += (gb.Vol[0] * PU1Table[fp8_24_to_u32(soundChannelPos[0])]);
|
||||
}
|
||||
if ((gb.DAC[1]) && (REG_NR52 & 0x02)) {
|
||||
if (REG_NR51 & 0x20)
|
||||
outputL += gb.Vol[1] * PU2Table[(int)(soundChannelPos[1])] / 15.0f;
|
||||
outputL += (gb.Vol[1] * PU2Table[fp8_24_to_u32(soundChannelPos[1])]);
|
||||
if (REG_NR51 & 0x02)
|
||||
outputR += gb.Vol[1] * PU2Table[(int)(soundChannelPos[1])] / 15.0f;
|
||||
outputR += (gb.Vol[1] * PU2Table[fp8_24_to_u32(soundChannelPos[1])]);
|
||||
}
|
||||
if ((REG_NR30 & 0x80) && (REG_NR52 & 0x04)) {
|
||||
if (REG_NR51 & 0x40)
|
||||
outputL += gb.Vol[2] * gb.WAVRAM[(int)(soundChannelPos[2])] / 4.0f;
|
||||
outputL += gb.Vol[2] * (gb.WAVRAM[fp8_24_to_u32(soundChannelPos[2])] >> 2);
|
||||
if (REG_NR51 & 0x04)
|
||||
outputR += gb.Vol[2] * gb.WAVRAM[(int)(soundChannelPos[2])] / 4.0f;
|
||||
outputR += gb.Vol[2] * (gb.WAVRAM[fp8_24_to_u32(soundChannelPos[2])] >> 2);
|
||||
}
|
||||
if ((gb.DAC[3]) && (REG_NR52 & 0x08)) {
|
||||
bool32 lfsrMode = ((REG_NR43 & 0x08) == 8);
|
||||
ch4Samples += freqTableNSE[REG_SOUND4CNT_H & 0xFF] / sampleRate;
|
||||
int ch4Out = 0;
|
||||
ch4Samples += freqTableNSE[REG_SOUND4CNT_H & (ARRAY_COUNT(freqTableNSE) - 1)];
|
||||
s8 ch4Out = 0;
|
||||
if (gb.ch4LFSR[lfsrMode] & 1) {
|
||||
ch4Out++;
|
||||
} else {
|
||||
ch4Out--;
|
||||
}
|
||||
int avgDiv = 1;
|
||||
while (ch4Samples >= 1) {
|
||||
avgDiv++;
|
||||
bool8 lfsrCarry = 0;
|
||||
if (gb.ch4LFSR[lfsrMode] & 2)
|
||||
lfsrCarry ^= 1;
|
||||
gb.ch4LFSR[lfsrMode] >>= 1;
|
||||
if (gb.ch4LFSR[lfsrMode] & 2)
|
||||
lfsrCarry ^= 1;
|
||||
if (lfsrCarry)
|
||||
gb.ch4LFSR[lfsrMode] |= lfsrMax[lfsrMode];
|
||||
if (gb.ch4LFSR[lfsrMode] & 1) {
|
||||
ch4Out++;
|
||||
} else {
|
||||
ch4Out--;
|
||||
}
|
||||
ch4Samples--;
|
||||
u8 steps = fp8_24_to_u32(ch4Samples);
|
||||
ch4Samples = fp8_24_fractional_part(ch4Samples);
|
||||
|
||||
u16 lfsr = gb.ch4LFSR[lfsrMode];
|
||||
u16 lfsrMask = lfsrMax[lfsrMode];
|
||||
|
||||
for (u8 i = 0; i < steps; i++) {
|
||||
// Comments to show what the bit
|
||||
// manipulation here is representing
|
||||
|
||||
// if (gb.ch4LFSR[lfsrMode] & 2)
|
||||
u16 lfsrCarry = (lfsr >> 1) & 1;
|
||||
lfsr >>= 1;
|
||||
// if (gb.ch4LFSR[lfsrMode] & 2)
|
||||
lfsrCarry ^= (lfsr >> 1) & 1;
|
||||
// if (lfsrCarry) gb.ch4LFSR[lfsrMode] |= lfsrMax[lfsrMode];
|
||||
lfsr |= -lfsrCarry & lfsrMask;
|
||||
// if (gb.ch4LFSR[lfsrMode] & 1)
|
||||
ch4Out += (lfsr & 1) ? 1 : -1;
|
||||
}
|
||||
float sample = ch4Out;
|
||||
if (avgDiv > 1)
|
||||
sample /= avgDiv;
|
||||
gb.ch4LFSR[lfsrMode] = lfsr;
|
||||
|
||||
// NOTE: if we convert this to int before multiplying by volume
|
||||
// the waves sound effect sounds better
|
||||
fixed8_24 sample = ch4Out * ch4StepsScale[steps];
|
||||
|
||||
// Muliply by the sample and then shift to make 8.24 again
|
||||
if (REG_NR51 & 0x80)
|
||||
outputL += gb.Vol[3] * sample / 15.0f;
|
||||
outputL += ((s64)sample * volScale[gb.Vol[3]]) >> 24;
|
||||
if (REG_NR51 & 0x08)
|
||||
outputR += gb.Vol[3] * sample / 15.0f;
|
||||
outputR += ((s64)sample * volScale[gb.Vol[3]]) >> 24;
|
||||
}
|
||||
}
|
||||
outBuffer[0] = outputL * 0.25f;
|
||||
outBuffer[1] = outputR * 0.25f;
|
||||
outBuffer[0] = (outputL >> 2);
|
||||
outBuffer[1] = (outputR >> 2);
|
||||
}
|
||||
}
|
||||
|
||||
float *cgb_get_buffer() { return gb.outBuffer; }
|
||||
fixed8_24 *cgb_get_buffer() { return gb.outBuffer; }
|
||||
@@ -5,9 +5,9 @@
|
||||
#include "platform/platform.h"
|
||||
#include "platform/shared/audio/cgb_audio.h"
|
||||
|
||||
static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSource *chan, struct WaveData *wav, float *pcmBuffer,
|
||||
static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSource *chan, struct WaveData *wav, fixed8_24 *pcmBuffer,
|
||||
u16 samplesPerFrame, float sampleRateReciprocal);
|
||||
static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 samplesPerFrame, float *pcmBuffer, u8 dmaCounter,
|
||||
static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 samplesPerFrame, fixed8_24 *pcmBuffer, u8 dmaCounter,
|
||||
u16 maxBufSize);
|
||||
static inline bool32 TickEnvelope(struct MixerSource *chan, struct WaveData *wav);
|
||||
static void ChnVolSetAsm(struct MixerSource *chan, struct MP2KTrack *track);
|
||||
@@ -25,12 +25,15 @@ static void ChnVolSetAsm(struct MixerSource *chan, struct MP2KTrack *track);
|
||||
#define FLOOR_DIV_POW2(a, b) ((a) > 0 ? (a) / (b) : (((a) + 1 - (b)) / (b)))
|
||||
#endif
|
||||
|
||||
static float audioBuffer[PCM_DMA_BUF_SIZE];
|
||||
static s16 audioBuffer[PCM_DMA_BUF_SIZE];
|
||||
static struct SoundMixerState sSoundInfo = { 0 };
|
||||
struct SoundMixerState *SOUND_INFO_PTR = &sSoundInfo;
|
||||
|
||||
void SoundMain(void)
|
||||
{
|
||||
#if !ENABLE_AUDIO
|
||||
return;
|
||||
#endif
|
||||
struct SoundMixerState *mixer = SOUND_INFO_PTR;
|
||||
|
||||
if (mixer->lockStatus != ID_NUMBER) {
|
||||
@@ -54,7 +57,7 @@ void SoundMain(void)
|
||||
mixer->CgbSound();
|
||||
|
||||
s32 samplesPerFrame = mixer->samplesPerFrame;
|
||||
float *pcmBuffer = mixer->pcmBuffer;
|
||||
fixed8_24 *pcmBuffer = mixer->pcmBuffer;
|
||||
s32 dmaCounter = mixer->dmaCounter;
|
||||
|
||||
if (dmaCounter > 1) {
|
||||
@@ -65,7 +68,7 @@ void SoundMain(void)
|
||||
cgb_audio_generate(samplesPerFrame);
|
||||
}
|
||||
|
||||
static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 samplesPerFrame, float *pcmBuffer, u8 dmaCounter,
|
||||
static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 samplesPerFrame, fixed8_24 *pcmBuffer, u8 dmaCounter,
|
||||
u16 maxBufSize)
|
||||
{
|
||||
u32 reverb = mixer->reverb;
|
||||
@@ -73,8 +76,8 @@ static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 sa
|
||||
// The vanilla reverb effect outputs a mono sound from four sources:
|
||||
// - L/R channels as they were mixer->framesPerDmaCycle frames ago
|
||||
// - L/R channels as they were (mixer->framesPerDmaCycle - 1) frames ago
|
||||
float *tmp1 = pcmBuffer;
|
||||
float *tmp2;
|
||||
fixed8_24 *tmp1 = pcmBuffer;
|
||||
fixed8_24 *tmp2;
|
||||
if (dmaCounter == 2) {
|
||||
tmp2 = mixer->pcmBuffer;
|
||||
} else {
|
||||
@@ -82,8 +85,8 @@ static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 sa
|
||||
}
|
||||
u16 i = 0;
|
||||
do {
|
||||
float s = tmp1[0] + tmp1[1] + tmp2[0] + tmp2[1];
|
||||
s *= ((float)reverb / 512.0f);
|
||||
fixed8_24 s = tmp1[0] + tmp1[1] + tmp2[0] + tmp2[1];
|
||||
s = (s * reverb) >> 9;
|
||||
tmp1[0] = tmp1[1] = s;
|
||||
tmp1 += 2;
|
||||
tmp2 += 2;
|
||||
@@ -92,7 +95,7 @@ static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 sa
|
||||
// memset(pcmBuffer, 0, samplesPerFrame);
|
||||
// memset(pcmBuffer + maxBufSize, 0, samplesPerFrame);
|
||||
for (int i = 0; i < samplesPerFrame; i++) {
|
||||
float *dst = &pcmBuffer[i * 2];
|
||||
fixed8_24 *dst = &pcmBuffer[i * 2];
|
||||
dst[1] = dst[0] = 0.0f;
|
||||
}
|
||||
}
|
||||
@@ -225,7 +228,7 @@ static inline bool32 TickEnvelope(struct MixerSource *chan, struct WaveData *wav
|
||||
}
|
||||
}
|
||||
|
||||
static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSource *chan, struct WaveData *wav, float *pcmBuffer,
|
||||
static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSource *chan, struct WaveData *wav, fixed8_24 *pcmBuffer,
|
||||
u16 samplesPerFrame, float sampleRateReciprocal)
|
||||
{ /*, [[[]]]) {*/
|
||||
u8 v = chan->data.sound.envelopeVol * (mixer->masterVol + 1) / 16U;
|
||||
@@ -240,15 +243,19 @@ static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSour
|
||||
}
|
||||
s32 samplesLeftInWav = chan->data.sound.ct;
|
||||
s8 *current = chan->current;
|
||||
signed envR = chan->data.sound.envelopeVolR;
|
||||
signed envL = chan->data.sound.envelopeVolL;
|
||||
|
||||
fixed8_24 envR = chan->data.sound.envelopeVolR << 9; // (* 32768)
|
||||
fixed8_24 envL = chan->data.sound.envelopeVolL << 9;
|
||||
|
||||
if (chan->type & TONEDATA_TYPE_CGB) {
|
||||
for (u16 i = 0; i < samplesPerFrame; i++, pcmBuffer += 2) {
|
||||
s8 c = *(current++);
|
||||
|
||||
pcmBuffer[1] += (c * envR) / 32768.0f;
|
||||
pcmBuffer[0] += (c * envL) / 32768.0f;
|
||||
// Creates a value between -32768 and 32768
|
||||
// So shift by 9 to make this between -1 and 1
|
||||
// in 8.24
|
||||
pcmBuffer[1] += (c * envR);
|
||||
pcmBuffer[0] += (c * envL);
|
||||
if (--samplesLeftInWav == 0) {
|
||||
samplesLeftInWav = loopLen;
|
||||
if (loopLen != 0) {
|
||||
@@ -263,8 +270,8 @@ static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSour
|
||||
chan->data.sound.ct = samplesLeftInWav;
|
||||
chan->current = current;
|
||||
} else {
|
||||
float finePos = chan->data.sound.fw;
|
||||
float romSamplesPerOutputSample = chan->data.sound.freq * sampleRateReciprocal;
|
||||
fixed8_24 finePos = chan->data.sound.fw;
|
||||
fixed8_24 romSamplesPerOutputSample = float_to_fp8_24(chan->data.sound.freq * sampleRateReciprocal);
|
||||
|
||||
s16 b = current[0];
|
||||
s16 m = current[1] - b;
|
||||
@@ -273,15 +280,15 @@ static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSour
|
||||
for (u16 i = 0; i < samplesPerFrame; i++, pcmBuffer += 2) {
|
||||
// Use linear interpolation to calculate a value between the current sample in the wav
|
||||
// and the next sample. Also cancel out the 9.23 stuff
|
||||
float sample = (finePos * m) + b;
|
||||
s32 sample = fp8_24_to_u32((s64)finePos * m) + b;
|
||||
|
||||
pcmBuffer[1] += (sample * envR) / 32768.0f;
|
||||
pcmBuffer[0] += (sample * envL) / 32768.0f;
|
||||
pcmBuffer[1] += (sample * envR);
|
||||
pcmBuffer[0] += (sample * envL);
|
||||
|
||||
finePos += romSamplesPerOutputSample;
|
||||
u32 newCoarsePos = finePos;
|
||||
u32 newCoarsePos = fp8_24_to_u32(finePos);
|
||||
if (newCoarsePos != 0) {
|
||||
finePos -= (int)finePos;
|
||||
finePos = fp8_24_fractional_part(finePos);
|
||||
samplesLeftInWav -= newCoarsePos;
|
||||
if (samplesLeftInWav <= 0) {
|
||||
if (loopLen != 0) {
|
||||
@@ -905,25 +912,28 @@ void m4aSoundVSync(void)
|
||||
struct SoundMixerState *mixer = SOUND_INFO_PTR;
|
||||
if (mixer->lockStatus - ID_NUMBER <= 1) {
|
||||
s32 samplesPerFrame = mixer->samplesPerFrame * 2;
|
||||
float *m4aBuffer = mixer->pcmBuffer;
|
||||
float *cgbBuffer = cgb_get_buffer();
|
||||
fixed8_24 *m4aBuffer = mixer->pcmBuffer;
|
||||
fixed8_24 *cgbBuffer = cgb_get_buffer();
|
||||
s32 dmaCounter = mixer->dmaCounter;
|
||||
bool8 shouldQueue = FALSE;
|
||||
|
||||
if (dmaCounter > 1) {
|
||||
m4aBuffer += samplesPerFrame * (mixer->framesPerDmaCycle - (dmaCounter - 1));
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < samplesPerFrame; i++) {
|
||||
audioBuffer[i] = m4aBuffer[i] + cgbBuffer[i];
|
||||
if (audioBuffer[i] != 0) {
|
||||
shouldQueue = TRUE;
|
||||
}
|
||||
// Sample is fixed 8.24 with a value of -1 to 1
|
||||
// but when we add we divide by 8 to add some headroom
|
||||
// and make the mix a much more managable volume
|
||||
fixed8_24 sample = (m4aBuffer[i] + cgbBuffer[i]) >> 3;
|
||||
|
||||
// 1 in 8.24 format is 1 << 24
|
||||
// 32768 is size expected for s16 audio
|
||||
// 32768 = 1 << 15
|
||||
// 24 - 15 = 9
|
||||
audioBuffer[i] = sample >> 9;
|
||||
}
|
||||
|
||||
if (shouldQueue) {
|
||||
Platform_QueueAudio(audioBuffer, samplesPerFrame * 4);
|
||||
}
|
||||
Platform_QueueAudio(audioBuffer, samplesPerFrame * sizeof(s16));
|
||||
if ((s8)(--mixer->dmaCounter) <= 0)
|
||||
mixer->dmaCounter = mixer->framesPerDmaCycle;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
struct DMATransfer DMAList[DMA_COUNT] = { 0 };
|
||||
|
||||
void RunDMAs(u32 type)
|
||||
void RunDMAs(DmaStartTypes type)
|
||||
{
|
||||
for (int dmaNum = 0; dmaNum < DMA_COUNT; dmaNum++) {
|
||||
struct DMATransfer *dma = &DMAList[dmaNum];
|
||||
@@ -124,7 +124,7 @@ void DmaStop(int dmaNum)
|
||||
|
||||
void DmaWait(int dmaNum)
|
||||
{
|
||||
vu32 *ctrlRegs = ®_DMA0CNT;
|
||||
vu32 *ctrlRegs = (vu32 *)®_DMA0CNT;
|
||||
#if !USE_NEW_DMA
|
||||
while (ctrlRegs[dmaNum * 3] & (DMA_ENABLE << 16))
|
||||
;
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include <xinput.h>
|
||||
#include "gba/io_reg.h"
|
||||
#include "gba/types.h"
|
||||
#include "gba/io_reg.h"
|
||||
#include "platform/shared/input.h"
|
||||
|
||||
#define STICK_THRESHOLD 0.5f
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -473,4 +473,4 @@ void *Platform_realloc(void *ptr, size_t numBytes)
|
||||
}
|
||||
void Platform_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); }
|
||||
|
||||
void Platform_QueueAudio(const u8 *data, u32 numBytes) { }
|
||||
void Platform_QueueAudio(const s16 *data, u32 numBytes) { }
|
||||
+3
-3
@@ -9,7 +9,7 @@
|
||||
#include "animation_commands.h"
|
||||
#include "platform/platform.h"
|
||||
|
||||
#if !PLATFORM_GBA && !PLATFORM_SDL
|
||||
#if !PLATFORM_GBA && RENDERER != RENDERER_SOFTWARE
|
||||
extern void Platform_DisplaySprite(Sprite *sprite, u8 oamPaletteNum);
|
||||
extern void Platform_TransformSprite(Sprite *sprite, SpriteTransform *transform);
|
||||
#endif
|
||||
@@ -395,7 +395,7 @@ NONMATCH("asm/non_matching/engine/TransformSprite.inc", void TransformSprite(Spr
|
||||
// sp24 = s
|
||||
UnkSpriteStruct big;
|
||||
const SpriteOffset *dimensions = s->dimensions;
|
||||
#if PORTABLE && (RENDERER != RENDERER_SOFTWARE)
|
||||
#if PORTABLE && RENDERER != RENDERER_SOFTWARE
|
||||
Platform_TransformSprite(s, transform);
|
||||
return;
|
||||
#endif
|
||||
@@ -727,7 +727,7 @@ void DisplaySprite(Sprite *sprite)
|
||||
oam->split.paletteNum += sprite->palId;
|
||||
#endif
|
||||
|
||||
#if !PLATFORM_GBA && !PLATFORM_SDL
|
||||
#if !PLATFORM_GBA && RENDERER != RENDERER_SOFTWARE
|
||||
// TEMP
|
||||
// Quick hack for getting output in OpenGL test
|
||||
// The whole function call should be replaced by this!
|
||||
|
||||
Vendored
+1
-1
@@ -31,7 +31,7 @@ SourceFileType GetFileType(std::string& path)
|
||||
|
||||
std::string extension = path.substr(pos + 1);
|
||||
|
||||
if (extension == "c")
|
||||
if (extension == "c" || extension == "cc")
|
||||
return SourceFileType::Cpp;
|
||||
else if (extension == "s")
|
||||
return SourceFileType::Asm;
|
||||
|
||||
Reference in new issue
Block a user