Compare commits

..

22 Commits

Author SHA1 Message Date
profi200 e63ec1404f
Small fixes/cleanup. 2020-12-24 12:40:39 +01:00
profi200 a719aa2864
Moved lots of code out of main.c/cleanup. 2020-12-19 22:30:43 +01:00
profi200 29413979fa
Fixed the oversaturation in the output by using a lower gamma. This is roughly tuned for launch day o3DS. If you want the previous colors back set inGamma to 2.2 and outGamma to 1.21.
Make path creation faster in case it already exists.
2020-12-03 18:23:13 +01:00
profi200 48def49f8b
Use relative paths where possible. 2020-11-29 22:52:13 +01:00
profi200 31bbcbfe25
Added some filter options to the config. 2020-11-28 17:18:58 +01:00
profi200 96eebb01db
Updated fatfs to R0.14. 2020-11-23 15:23:12 +01:00
profi200 dd68d381ac
Added basic config file support (thanks to benhoyt for his inih lib). 2020-11-23 02:45:47 +01:00
profi200 5f25739286
Enabled more debugging techniques by default in debug builds.
Added more Arm intrinsics.
ARM7 stub now waits for REG_VCOUNT == 126 (same as after BIOS intro).
Enable ROM mirroring for all 8 Mbit games instead of just Classic NES Series.
Other misc. changes.
2020-11-22 01:47:58 +01:00
profi200 5316c8938d
Avoid errors when the last ROM launch dir doesn't exist anymore.
Other small fixes.
2020-10-25 23:01:30 +01:00
profi200 c87769a06e
Added returning to the last dir a ROM was launched from on next boot. Fixes #21. 2020-10-25 22:00:44 +01:00
profi200 ffb32cca9c
Some small, unimportant changes. 2020-10-24 21:53:08 +02:00
profi200 dac935f66d
Made the file browser sorting a bit faster. 2020-10-24 21:53:08 +02:00
profi200 ac33d98ad5
Fixed file browser sorting. 2020-10-24 21:53:08 +02:00
profi200 1caafaf5b3
Port some of the changes from arm_intrinsic.h to arm.h. 2020-10-24 21:53:08 +02:00
profi200 179ea504d0
Added a basic screenshot feature dumping the GPU input texture by pressing Y. Fixes #19. 2020-10-24 21:53:08 +02:00
profi200 07f6f01d92
Added game database search code (and a debug menu for it).
Mimic ROM "open bus" (not 100% accurate) and ROM mirroring. Fixes #20.
Implemented some useful ARM instruction intrinsics.
2020-10-24 21:52:14 +02:00
profi200 8fdc74a3c4
Added a temporary workaround to prevent panics if booted from bootloaders with broken screen init. 2020-09-25 00:59:45 +02:00
profi200 ef79b4343d
Use anonymous structs instead of void for public kernel API. 2020-09-14 16:24:03 +02:00
profi200 b8f4d5cd53
More cleanup and bug fixes. 2020-09-12 14:50:24 +02:00
profi200 6826d5d660
Added a workaround for a minor scheduling bug + documentation. 2020-09-08 16:17:07 +02:00
profi200 02e9fa9830
Refactor. Moved code outside of the hardware drivers that doesn't belong there. 2020-09-08 16:13:58 +02:00
profi200 f028745f52
First public release of my tiny kernel. 2020-09-05 17:20:38 +02:00
193 changed files with 46445 additions and 3796 deletions

View File

@ -1,52 +0,0 @@
name: C/C++ CI
on:
push:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
container: devkitpro/devkitarm
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
submodules: recursive
- name: Get ctr_firm_builder commit
run: echo "FIRM_BUILDER_COMMIT=$(git ls-remote https://github.com/derrekr/ctr_firm_builder.git HEAD | cut -f1)" >> $GITHUB_ENV
- name: Cache ctr_firm_builder
id: cache-firm-builder
uses: actions/cache@v4
with:
path: ctr_firm_builder
key: ${{ runner.os }}-${{ env.FIRM_BUILDER_COMMIT }}
- name: Install ctr_firm_builder dependencies
if: steps.cache-firm-builder.outputs.cache-hit != 'true'
run: |
apt-get update
apt-get -y install gcc
- name: Build ctr_firm_builder
if: steps.cache-firm-builder.outputs.cache-hit != 'true'
run: |
git clone --depth 1 --recurse-submodules https://github.com/derrekr/ctr_firm_builder.git
cd ctr_firm_builder
make
- name: Build project
run: |
export PATH=$PWD/ctr_firm_builder:$PATH
make nightly
echo ${{ github.sha }} >> ./nightly/nightly_commit.txt
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: open_agb_firm_nightly
path: ./nightly
if-no-files-found: error

20
.gitignore vendored
View File

@ -1,9 +1,11 @@
/.*
!/.git*
/arm[19]*/build/
/arm[19]*/open_agb_firm[19]*.*
/tools/gba-db/gba_db.*
!/tools/gba-db/gba_db.py
/tools/gba-db/gba.*
!/tools/gba-db/gba.csv
/open_agb_firm*.*
arm9/build/
arm11/build/
eclipse_project/
*.sublime-project
*.sublime-workspace
arm9/open_agb_firm9.bin
arm11/open_agb_firm11.bin
arm9/open_agb_firm9.elf
arm11/open_agb_firm11.elf
open_agb_firm.firm
open_agb_firm*.7z

9
.gitmodules vendored
View File

@ -1,9 +0,0 @@
[submodule "libraries/libn3ds"]
path = libraries/libn3ds
url = https://github.com/profi200/libn3ds.git
[submodule "tools/lgyFbScaler/lodepng"]
path = tools/lgyFbScaler/lodepng
url = https://github.com/lvandeve/lodepng.git
[submodule "libraries/inih"]
path = libraries/inih
url = https://github.com/benhoyt/inih.git

View File

@ -9,25 +9,16 @@ export TARGET := open_agb_firm
ENTRY9 := 0x08000040
ENTRY11 := 0x1FF89034
SECTION0_ADR := 0x08000040
ifeq ($(strip $(USE_FIRMTOOL)),1)
SECTION0_TYPE := NDMA
else
SECTION0_TYPE := 0
endif
SECTION0_FILE := arm9/$(TARGET)9.bin
SECTION1_ADR := 0x1FF89000
ifeq ($(strip $(USE_FIRMTOOL)),1)
SECTION1_TYPE := XDMA
else
SECTION1_TYPE := 1
endif
SECTION1_FILE := arm11/$(TARGET)11.bin
export VERS_STRING := $(shell git describe --tags --match v[0-9]* --abbrev=8 | sed 's/-[0-9]*-g/-/i')
export VERS_MAJOR := $(shell echo "$(VERS_STRING)" | sed 's/v\([0-9]*\)\..*/\1/i')
export VERS_MINOR := $(shell echo "$(VERS_STRING)" | sed 's/.*\.\([0-9]*\).*/\1/')
NPROC := $(shell nproc)
.PHONY: checkarm9 checkarm11 clean release
@ -39,66 +30,35 @@ all: checkarm9 checkarm11 $(TARGET).firm
#---------------------------------------------------------------------------------
checkarm9:
@$(MAKE) -j$(NPROC) --no-print-directory -C arm9
@$(MAKE) -j4 --no-print-directory -C arm9
#---------------------------------------------------------------------------------
checkarm11:
@$(MAKE) -j$(NPROC) --no-print-directory -C arm11
@$(MAKE) -j4 --no-print-directory -C arm11
#---------------------------------------------------------------------------------
$(TARGET).firm: arm9/$(TARGET)9.bin arm11/$(TARGET)11.bin
ifeq ($(strip $(USE_FIRMTOOL)),1)
firmtool build $(TARGET).firm -n $(ENTRY9) -e $(ENTRY11) -A $(SECTION0_ADR) $(SECTION1_ADR) \
-D $(SECTION0_FILE) $(SECTION1_FILE) -C $(SECTION0_TYPE) $(SECTION1_TYPE)
else
firm_builder $(TARGET).firm $(ENTRY9) $(ENTRY11) $(SECTION0_ADR) $(SECTION0_TYPE) \
$(SECTION0_FILE) $(SECTION1_ADR) $(SECTION1_TYPE) $(SECTION1_FILE)
endif
#---------------------------------------------------------------------------------
arm9/$(TARGET)9.bin:
@$(MAKE) -j$(NPROC) --no-print-directory -C arm9
@$(MAKE) -j4 --no-print-directory -C arm9
#---------------------------------------------------------------------------------
arm11/$(TARGET)11.bin:
@$(MAKE) -j$(NPROC) --no-print-directory -C arm11
@$(MAKE) -j4 --no-print-directory -C arm11
#---------------------------------------------------------------------------------
clean:
@$(MAKE) --no-print-directory -C arm9 clean
@$(MAKE) --no-print-directory -C arm11 clean
rm -fr $(TARGET).firm *.7z nightly
rm -f $(TARGET).firm *.7z
#---------------------------------------------------------------------------------
release: clean
@$(MAKE) -j$(NPROC) --no-print-directory -C arm9 NO_DEBUG=1
@$(MAKE) -j$(NPROC) --no-print-directory -C arm11 NO_DEBUG=1
ifeq ($(strip $(USE_FIRMTOOL)),1)
firmtool build $(TARGET).firm -n $(ENTRY9) -e $(ENTRY11) -A $(SECTION0_ADR) $(SECTION1_ADR) \
-D $(SECTION0_FILE) $(SECTION1_FILE) -C $(SECTION0_TYPE) $(SECTION1_TYPE)
else
@$(MAKE) -j4 --no-print-directory -C arm9 NO_DEBUG=1
@$(MAKE) -j4 --no-print-directory -C arm11 NO_DEBUG=1
firm_builder $(TARGET).firm $(ENTRY9) $(ENTRY11) $(SECTION0_ADR) $(SECTION0_TYPE) \
$(SECTION0_FILE) $(SECTION1_ADR) $(SECTION1_TYPE) $(SECTION1_FILE)
endif
@7z a -mx -m0=ARM -m1=LZMA $(TARGET)$(VERS_STRING).7z $(TARGET).firm
@7z u -mx -m0=LZMA $(TARGET)$(VERS_STRING).7z resources/gba_db.bin
@7z u -mx -m0=PPMD $(TARGET)$(VERS_STRING).7z libraries/libn3ds/LICENSE.txt libraries/libn3ds/libraries/fatfs/LICENSE.txt libraries/inih/LICENSE.txt LICENSE.txt README.md
@7z rn $(TARGET)$(VERS_STRING).7z resources/gba_db.bin 3ds/open_agb_firm/gba_db.bin libraries/libn3ds/LICENSE.txt LICENSE_libn3ds.txt libraries/libn3ds/libraries/fatfs/LICENSE.txt LICENSE_FatFs.txt libraries/inih/LICENSE.txt LICENSE_inih.txt
#---------------------------------------------------------------------------------
nightly: clean
@$(MAKE) -j$(NPROC) --no-print-directory -C arm9 NO_DEBUG=1
@$(MAKE) -j$(NPROC) --no-print-directory -C arm11 NO_DEBUG=1
ifeq ($(strip $(USE_FIRMTOOL)),1)
firmtool build $(TARGET).firm -n $(ENTRY9) -e $(ENTRY11) -A $(SECTION0_ADR) $(SECTION1_ADR) \
-D $(SECTION0_FILE) $(SECTION1_FILE) -C $(SECTION0_TYPE) $(SECTION1_TYPE)
else
firm_builder $(TARGET).firm $(ENTRY9) $(ENTRY11) $(SECTION0_ADR) $(SECTION0_TYPE) \
$(SECTION0_FILE) $(SECTION1_ADR) $(SECTION1_TYPE) $(SECTION1_FILE)
endif
@mkdir -p nightly/3ds/open_agb_firm
@cp -t nightly $(TARGET).firm LICENSE.txt README.md
@cp resources/gba_db.bin nightly/3ds/open_agb_firm
@cp libraries/libn3ds/LICENSE.txt nightly/LICENSE_libn3ds.txt
@cp libraries/libn3ds/libraries/fatfs/LICENSE.txt nightly/LICENSE_FatFs.txt
@cp libraries/inih/LICENSE.txt nightly/LICENSE_inih.txt
@7z u -mx -m0=PPMD $(TARGET)$(VERS_STRING).7z LICENSE.txt README.md

296
README.md
View File

@ -1,276 +1,44 @@
# open_agb_firm
open_agb_firm is a bare metal interface for *natively* running GBA games and homebrew using the 3DS's built-in GBA hardware.
open_agb_firm is also a complete and better alternative to GBA VC injects (AGB_FIRM), allowing for:
* Launching GBA files directly from the SD card
* Writing save files directly to the SD card
* Automatic save type configuration using an included database
* User configuration, such as gamma settings
* Button remapping
* Border support for 1:1 scaling mode
* Gamma correction to fix the washed out look of games
* Color correction to mimic the look of the GBA/DS phat LCD
* And more to come!
Unlike AGB_FIRM open_agb_firm is not affected by the famous bug where the video output wraps around leaving garbled lines at the bottom of the screen. SD cluster size doesn't matter.
open_agb_firm is a bare metal app for running GBA homebrew/games using the 3DS builtin GBA hardware.
## Disclaimer
open_agb_firm is currently in beta. While open_agb_firm is relatively stable and safe to use, some quirks that have not been fixed. See [Known Issues](#known-issues) for more information.
We are not responsible for any damage that may occur to your system as a direct or indirect result of you using open_agb_firm.
Additionally, we are not responsible for any damage that may occur to your system as a direct or indirect result of you using open_agb_firm.
## How to build
To compile open_agb_firm you need
* [devkitARM](https://sourceforge.net/projects/devkitpro/)
* [Corelink DMA-330 assembler](https://github.com/profi200/dma330as)
* [CTR firm builder](https://github.com/derrekr/ctr_firm_builder)
## Setup
* Download the [latest release](https://github.com/profi200/open_agb_firm/releases/latest) and extract it.
* Copy the `open_agb_firm.firm` file to your 3DS's SD card at `/luma/payloads` if you're using Luma3DS or elsewhere if you're using fastboot3DS.
* Copy the `3ds` folder to the root of your 3DS's SD card. Merge folders if asked.
* Launch open_agb_firm using Luma3DS by holding START while booting your 3DS or assign it to a slot if you're using fastboot3DS.
* After open_agb_firm launches, use the file browser to navigate to a `.gba` ROM to run.
installed in your system. Additionally you need 7-Zip or on Linux p7z installed to make release builds. Also make sure the CTR firm builder and dma330as binaries are in your $PATH environment variable and accessible to the Makefile. Build open_agb_firm as debug build via `make` or as release build via `make release`.
## Controls
A/B/L/R/START/SELECT - GBA buttons, respectively
SELECT+Y - Dump hardware frame output to `/3ds/open_agb_firm/screenshots/YYYY_MM_DD_HH_MM_SS.bmp`
* The file name is the current date and time from your real-time clock.
* If the screen output freezes, press HOME to fix it. This is a hard to track down bug that will be fixed.
X+UP/DOWN - Adjust screen brightness up or down by `backlightSteps` units.
X+LEFT - Turn off LCD backlight.
X+RIGHT - Turn on LCD backlight.
Hold the X button while launching a game to skip applying patches (if present)
Hold the power button to turn off the 3DS.
## Configuration
Settings are stored in `/3ds/open_agb_firm/config.ini`.
### General
General settings.
`u8 backlight` - Backlight brightness in luminance (cd/m²).
* Default: `64`
* Possible values:
* Old 3DS: `20`-`117`
* New 3DS: `16`-`142`
* Values ≤`64` are recommended.
* Hardware calibration from your CTRNAND is required to get the correct brightness for both LCDs.
`u8 backlightSteps` - How much to adjust backlight brightness by.
* Default: `5`
`bool directBoot` - Skip GBA BIOS intro at game startup.
* Default: `false`
`bool useGbaDb` - Use `gba_db.bin` to get save types.
* Default: `true`
`bool useSavesFolder` - Use `/3ds/open_agb_firm/saves` for save files instead of the ROM directory.
* Default: `true`
### Video
Video-related settings.
`string scaler` - Video scaler.
* Default: `matrix`
* Options: `none`, `bilinear`, `matrix`
`string colorProfile` - Color correction profile.
* Default: `none`
* Options:
* `none` Disable all color correction options.
* `gba` Game Boy Advance.
* `gb_micro` Game Boy micro.
* `gba_sp101` Game Boy Advance SP (AGS-101).
* `nds` Nintendo DS (DS phat).
* `ds_lite` Nintendo DS lite.
* `nso` Nintendo Switch Online.
* `vba` Visual Boy Advance/No$GBA full.
* `identity` No color space conversion.
* If you just want less saturated colors or to change other basic settings like contrast or brightness then set this to `identity`.
* Due to most 2/3DS LCDs not being calibrated correctly from factory the look may not match exactly what you see on real hardware.
* Due to a lot of extra RAM access and extra CPU processing per frame, battery runtime is affected with color profiles other than `none`.
`float contrast` - Screen gain. No effect when `colorProfile=none`.
* Default: `1.0`
`float brightness` - Screen lift. No effect when `colorProfile=none`.
* Default: `0.0`
`float saturation` - Screen saturation. No effect when `colorProfile=none`.
* Default: `1.0`
### Audio
Audio settings.
`string audioOut` - Audio output.
* Default: `auto`
* Options: `auto`, `speakers`, `headphones`
`s8 volume` - Audio volume. Values above 48 mean control via volume slider. Range -128 (muted) to -20 (100%). Avoid the range -19 to 48.
* Default: `127`
### Input
Input settings. Each entry allows one or multiple buttons. Buttons are separated by a `,` without spaces.
Allowed buttons are `A B SELECT START RIGHT LEFT UP DOWN R L X Y TOUCH CP_RIGHT CP_LEFT CP_UP CP_DOWN`.
TOUCH reacts to all touchscreen presses. The CP in front is short for Circle-Pad.
Note that button mappings can cause input lag of up to 1 frame depending on when the game reads inputs. For this reason the default mapping of the Circle-Pad to D-Pad is no longer provided.
`A` - Button map for the A button.
* Default: `none`
`B` - Button map for the B button.
* Default: `none`
`SELECT` - Button map for the SELECT button.
* Default: `none`
`START` - Button map for the START button.
* Default: `none`
`RIGHT` - Button map for the RIGHT button.
* Default: `none`
`LEFT` - Button map for the LEFT button.
* Default: `none`
`UP` - Button map for the UP button.
* Default: `none`
`DOWN` - Button map for the DOWN button.
* Default: `none`
`R` - Button map for the R button.
* Default: `none`
`L` - Button map for the L button.
* Default: `none`
Example which maps the D-Pad and Circle-Pad to the GBA D-Pad:
```
[input]
RIGHT=RIGHT,CP_RIGHT
LEFT=LEFT,CP_LEFT
UP=UP,CP_UP
DOWN=DOWN,CP_DOWN
```
### Game
Game-specific settings. Only intended to be used in the per-game settings (romName.ini in `/3ds/open_agb_firm/saves`).
`u8 saveSlot` - Savegame slot (0-9).
* Default: `0`
`string saveType` - Override to use a specific save type.
* Default: `auto`
* Options starting with `rom_256m` are intended for 32 MiB games. Options ending with `rtc` enable the hardware real-time clock:
* `eeprom_8k`
* `rom_256m_eeprom_8k`
* `eeprom_64k`
* `rom_256m_eeprom_64k`
* `flash_512k_atmel_rtc`
* `flash_512k_atmel`
* `flash_512k_sst_rtc`
* `flash_512k_sst`
* `flash_512k_panasonic_rtc`
* `flash_512k_panasonic`
* `flash_1m_macronix_rtc`
* `flash_1m_macronix`
* `flash_1m_sanyo_rtc`
* `flash_1m_sanyo`
* `sram_256k`
* `none`
* `auto`
### Advanced
Options for advanced users. No pun intended.
`bool saveOverride` - Open save type override menu after selecting a game.
* Default: `false`
`string defaultSave` - Save type default when save type is not in `gba_db.bin` and cannot be autodetected. Same options as for `saveType` above except `auto` is not supported.
* Default: `sram_256k`
## Patches
open_agb_firm supports automatically applying IPS and UPS patches. To use a patch, rename the patch file to match the ROM file name (without the extension).
* If you wanted to apply an IPS patch to `example.gba`, rename the patch file to `example.ips`
## Known Issues
## Known issues
This section is reserved for a listing of known issues. At present only this remains:
* Sleep mode is not fully implemented.
* Using SELECT+Y to dump screen output to a file can freeze the screen output sometimes.
* Save type autodetection may still fail for certain games using EEPROM.
* Lack of settings.
* No cheats and other enhancements.
* Save type detection may still fail for certain games using EEPROM.
* No settings (including brightness control), no cheats and other enhancements.
If you happen to stumble over another bug, please [open an issue](https://github.com/profi200/open_agb_firm/issues) or contact profi200 via other platforms.
If you happen to stumble over another bug, please open an issue in the [official open_agb_firm repo on GitHub](https://github.com/profi200/open_agb_firm/issues) or contact me via other platforms.
## Hardware Limitations
open_agb_firm using the 3DS's built-in GBA hardware. Unfortunately, this comes with limitations compared to GBA emulators. This is a list of limitations we can't solve in software or are very hard to work around.
* \>32 MiB (>256 Mbit) games and homebrew.
* Games with extra hardware built into the cartridge (except real-time clocks). Patches are required.
* Proper save autodetection (can't find save type during gameplay).
* GBA serial port (aka Link Cable).
* \>32 KiB (>256 Kbit) SRAM (homebrew games/emulators).
* Reboots are required for switching between games.
* No save states. Very difficult to implement because no direct hardware access.
* Sound has lots of aliasing issues. No known workaround (hardware bug).
## Hardware limitations
This is a list of limitations we can't solve in software or are very hard to work around. This doesn't mean it will never happen (unless stated otherwise).
* 64 MiB (512 mbit) games. Not possible to support.
* Games with extra hardware built into the cartridge (except Real-Time Clock). Patches are required.
* GBA Serial port (aka. Link Cable).
* 64 KiB (512 kbit) SRAM (homebrew games/emulators). Not possible to support.
* Can't switch back to 3DS mode from GBA mode requiring a reboot for booting a different game.
* Savestates. Very difficult to implement because no direct hardware access.
## EEPROM Fixer
Most emulators output EEPROM saves differently than what open_agb_firm expects, making them incompatible. Fortunately, they are very easy to fix, using [this tool](https://exelotl.github.io/gba-eeprom-save-fix/) by exelotl.
## Troubleshooting
Known problems and the solution.
The tool also works vise versa, if you want to use a save generated by open_agb_firm with an emulator.
## FAQ
**Q: Why isn't open_agb_firm a normal 3DS app?**\
A: To access the 3DS's GBA hardware, open_agb_firm needs to run with full hardware access, which can only be provided by running as a FIRM.
**Q: Is this safe to use?**\
A: Of course! While open_agb_firm does run with full hardware access, a lot of work has been put in by several people to ensure that nothing unexpected happens. Some backend code from open_agb_firm is actually used in [fastboot3ds](https://github.com/derrekr/fastboot3DS)!
**Q: What games work with open_agb_firm?**\
A: In theory, all of them, except those that fall within the [hardware limitations](#hardware-limitations).
**Q: How can I increase the brightness?**\
A: Increase the value of the `backlight` setting in `config.ini`. See [Configuration](#configuration) for more information.
**Q: Why do the colors look off?**\
A: The default gamma settings are intended to make up for the washed out colors the 3DS LCD has. If they look weird to you, setting the `outGamma` setting to `2.2` might help.
**Q: Why do some of my ROM hacks/homebrew games have saving issues?**\
A: open_agb_firm resorts to save autodetection when it can't find an entry for the game it's running in `gba_db.bin` (which only contains data for official games), and it's a bit wonky for games that use EEPROM or misleading SDK save strings.
**Q: Why doesn't my save file from an emulator work?**\
A: There's a good chance that the save you're having issues with is an EEPROM save, which most emulators output differently. See [EEPROM Fixer](#eeprom-fixer).
**Q: My game doesn't save properly!**\
A: First, please ensure that the GBA ROM you are playing is not modified in any way, and matches its [No-Intro](https://datomatic.no-intro.org/) checksums. Second, make sure you aren't using an existing `.SAV` file, because some may have issues for various reasons. Third, make sure your [`gba_db.bin`](resources/gba_db.bin) is up-to-date. If everything seems to be in order but the game still doesn't save properly, please [open an issue](https://github.com/profi200/open_agb_firm/issues) so it can be fixed. In the meantime, the `useGbaDb` and `saveOverride` settings may be useful (see [Configuration](#configuration) for more information).
## Nightlies
If you want to test the latest changes you have 2 download options. The first is recommended.
**With GitHub account**\
Log into your account, go to the Actions tab at the top, click on the first entry and download the file under `Artifacts` (`open_agb_firm_nightly`).
**Without GitHub account**\
nightly.link is a thirdparty site to make builds available to everyone. I'm not affiliated with nightly.link or their developers and neither are they with GitHub. Use at your own risk.\
https://nightly.link/profi200/open_agb_firm/workflows/c-cpp/master/open_agb_firm_nightly.zip
## Compiling
To compile open_agb_firm, the following needs to be installed:
* [devkitARM](https://devkitpro.org/wiki/devkitPro_pacman)
* [CTR Firm Builder](https://github.com/derrekr/ctr_firm_builder) or [firmtool](https://github.com/TuxSH/firmtool)
Additionally, `p7zip` (or if available, `p7zip-full`) needs to be installed to make release builds. Also, make sure that the `dma330as` and `firm_builder`/`firmtool` binaries are in the PATH environment variable and accessible to the Makefile.
Clone this repository using `git clone --recurse-submodules https://github.com/profi200/open_agb_firm`and update via `git pull && git submodule update --init --recursive`.
Build open_agb_firm as a debug build via `make`, or as a release build via `make release`.
Problem: The game crashes/shows white or blackscreens or shows a savegame corrupt message.\
Solution: Try to delete the savegame file. If this doesn't help report the issue.\
Note: EEPROM saves made by some emulators are incompatible because they have every 8 bytes block endian swapped.
## License
You may use this under the terms of the GNU General Public License GPL v3 or the terms of any later revisions of the GPL. Refer to the provided `LICENSE.txt` file for further information.
You may use this under the terms of the GNU General Public License GPL v3 or under the terms of any later revisions of the GPL. Refer to the provided `LICENSE.txt` file for further information.
## Thanks to...
* **yellows8**
@ -279,17 +47,13 @@ You may use this under the terms of the GNU General Public License GPL v3 or the
* **Normmatt**
* **WinterMute**
* **ctrulib devs**
* **LumaTeam**
* **Luma 3DS devs**
* **devkitPro**
* **ChaN** (fatfs)
* **benhoyt** (inih)
* **fastboot3DS project**
* **MAME**
* **No-Intro**
* **Wolfvak, Sono and all the other people in #GodMode9 on freenode/Discord**
* **endrift, Extrems and all the other people in #mgba on Libera.Chat**
* **Oleh Prypin (oprypin) for nightly.link**
* **[hunterk and Pokefan531 for their amazing libretro shaders](https://forums.libretro.com/t/real-gba-and-ds-phat-colors/1540/220)**
* **Wolfvak, Sono and all the other people in #GodMode9 on IRC/Discord**
* **endrift, Extrems and all the other people in #mgba on Freenode**
* ...everyone who contributed to **3dbrew.org**
Copyright (C) 2024 derrek, profi200, d0k3
Copyright (C) 2020 derrek, profi200, d0k3

View File

@ -8,7 +8,6 @@ endif
TOPDIR ?= $(CURDIR)
include $(DEVKITARM)/base_rules
include $(TOPDIR)/../libraries/libn3ds/libn3ds11.mk
#---------------------------------------------------------------------------------
# TARGET is the name of the output
@ -19,10 +18,12 @@ include $(TOPDIR)/../libraries/libn3ds/libn3ds11.mk
#---------------------------------------------------------------------------------
#TARGET := $(notdir $(CURDIR))
BUILD := build
SOURCES += ../source ../source/arm11 ../libraries/inih
SOURCES := ../kernel/source ../source ../source/hardware ../source/arm11 \
../source/arm11/allocator ../source/arm11/hardware \
../source/arm11/util/rbtree ../thirdparty/inih
DATA :=
INCLUDES += ../include ../libraries
DEFINES := -D__ARM11__ -D__3DS__ -DLIBN3DS_LEGACY=1 -DVERS_STRING=\"$(VERS_STRING)\" \
INCLUDES := ../kernel/include ../include ../thirdparty
DEFINES := -DARM11 -D_3DS -DVERS_STRING=\"$(VERS_STRING)\" \
-DVERS_MAJOR=$(VERS_MAJOR) -DVERS_MINOR=$(VERS_MINOR)
ASSETS :=
@ -33,18 +34,18 @@ endif
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv6k+vfpv2 -mtune=mpcore -mfloat-abi=hard -mtp=soft -marm -mthumb-interwork -masm-syntax-unified
ARCH := -march=armv6k+vfpv2 -mtune=mpcore -mfloat-abi=hard -mtp=soft -marm -mthumb-interwork
CFLAGS := $(ARCH) -std=c23 -O2 -gdwarf-4 -flto -mword-relocations \
CFLAGS := $(ARCH) -std=c17 -O2 -g -flto -mword-relocations \
-ffunction-sections -fno-math-errno -Wall -Wextra
CFLAGS += $(INCLUDE) $(DEFINES)
CXXFLAGS := $(ARCH) -std=c++23 -O2 -gdwarf-4 -flto -fno-rtti -fno-exceptions \
CXXFLAGS := $(ARCH) -std=c++17 -O2 -g -flto -fno-rtti -fno-exceptions \
-mword-relocations -ffunction-sections -fno-math-errno -Wall -Wextra
CXXFLAGS += $(INCLUDE) $(DEFINES)
ASFLAGS := $(ARCH) -gdwarf-4 -flto $(INCLUDE) $(DEFINES)
LDFLAGS = $(ARCH) -gdwarf-4 -flto -specs=../arm11.specs -Wl,-Map,$(notdir $*.map) -nostartfiles
ASFLAGS := $(ARCH) -g -flto $(INCLUDE) $(DEFINES)
LDFLAGS = $(ARCH) -g -flto -specs=../arm11.specs -Wl,-Map,$(notdir $*.map) -nostartfiles
ifeq ($(strip $(NO_DEBUG)),)
CFLAGS := $(subst -flto,,$(CFLAGS)) -fstack-protector-strong -fno-inline

View File

@ -8,7 +8,6 @@ endif
TOPDIR ?= $(CURDIR)
include $(DEVKITARM)/base_rules
include $(TOPDIR)/../libraries/libn3ds/libn3ds9.mk
#---------------------------------------------------------------------------------
# TARGET is the name of the output
@ -19,10 +18,10 @@ include $(TOPDIR)/../libraries/libn3ds/libn3ds9.mk
#---------------------------------------------------------------------------------
#TARGET := $(notdir $(CURDIR))
BUILD := build
SOURCES += ../source/arm9
SOURCES := ../source ../source/hardware ../source/arm9 ../source/arm9/hardware ../thirdparty/fatfs
DATA :=
INCLUDES += ../include
DEFINES := -D__ARM9__ -D__3DS__ -DLIBN3DS_LEGACY=1 -DVERS_STRING=\"$(VERS_STRING)\" \
INCLUDES := ../include ../thirdparty
DEFINES := -DARM9 -D_3DS -DVERS_STRING=\"$(VERS_STRING)\" \
-DVERS_MAJOR=$(VERS_MAJOR) -DVERS_MINOR=$(VERS_MINOR)
ifneq ($(strip $(NO_DEBUG)),)
@ -32,25 +31,18 @@ endif
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv5te -mtune=arm946e-s -mfloat-abi=soft -mtp=soft -marm -mthumb-interwork -masm-syntax-unified
ARCH := -march=armv5te -mtune=arm946e-s -mfloat-abi=soft -mtp=soft -marm -mthumb-interwork
CFLAGS := $(ARCH) -std=c23 -O2 -gdwarf-4 -flto -mword-relocations \
CFLAGS := $(ARCH) -std=c17 -O2 -g -flto -mword-relocations \
-ffunction-sections -Wall -Wextra
CFLAGS += $(INCLUDE) $(DEFINES)
CXXFLAGS := $(ARCH) -std=c++23 -O2 -gdwarf-4 -flto -fno-rtti -fno-exceptions \
CXXFLAGS := $(ARCH) -std=c++17 -O2 -g -flto -fno-rtti -fno-exceptions \
-mword-relocations -ffunction-sections -Wall -Wextra
CXXFLAGS += $(INCLUDE) $(DEFINES)
ASFLAGS := $(ARCH) -gdwarf-4 -flto $(INCLUDE) $(DEFINES)
LDFLAGS = $(ARCH) -gdwarf-4 -flto -specs=../arm9.specs -Wl,-Map,$(notdir $*.map) -nostartfiles
ifeq ($(strip $(NO_DEBUG)),)
CFLAGS := $(subst -flto,,$(CFLAGS)) -fstack-protector-strong -fno-inline
CXXFLAGS := $(subst -flto,,$(CXXFLAGS)) -fstack-protector-strong -fno-inline
ASFLAGS := $(subst -flto,,$(ASFLAGS))
LDFLAGS := $(subst -flto,,$(LDFLAGS)) -fstack-protector-strong -fno-inline -Wl,-wrap=malloc,-wrap=calloc,-wrap=free
endif
ASFLAGS := $(ARCH) -g -flto $(INCLUDE) $(DEFINES)
LDFLAGS = $(ARCH) -g -flto -specs=../arm9.specs -Wl,-Map,$(notdir $*.map) -nostartfiles
LIBS :=

324
include/arm.h Normal file
View File

@ -0,0 +1,324 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !__ASSEMBLER__
#include "types.h"
#endif
// Program status register (CPSR/SPSR)
#define PSR_USER_MODE (16)
#define PSR_FIQ_MODE (17)
#define PSR_IRQ_MODE (18)
#define PSR_SVC_MODE (19)
#define PSR_ABORT_MODE (23)
#define PSR_UNDEF_MODE (27)
#define PSR_SYS_MODE (31)
#define PSR_MODE_MASK (PSR_SYS_MODE)
#define PSR_T (1<<5) // Thumb mode
#define PSR_F (1<<6) // Interrupts (FIQ) disable flag
#define PSR_I (1<<7) // Interrupts (IRQ) disable flag
#define PSR_A (1<<8) // Imprecise aborts disable flag
#define PSR_E (1<<9) // Big endian
#define PSR_J (1<<24) // Jazelle mode
#define PSR_Q (1<<27)
#define PSR_V (1<<28) // Overflow flag
#define PSR_C (1<<29) // Carry flag
#define PSR_Z (1<<30) // Zero flag
#define PSR_N (1<<31) // Negative flag
#define PSR_INT_OFF (PSR_I | PSR_F) // IRQ and FIQ disabled flags
#if !__ASSEMBLER__
#define MAKE_INTR_NO_INOUT(isVolatile, name, ...) \
ALWAYS_INLINE void __##name(void) \
{ \
if(isVolatile == 1) \
__asm__ volatile(#name : : : __VA_ARGS__); \
else \
__asm__(#name : : : __VA_ARGS__); \
}
#define MAKE_INTR_GET_REG(isVolatile, name, inst) \
ALWAYS_INLINE u32 __##name(void) \
{ \
u32 reg; \
if(isVolatile == 1) \
__asm__ volatile(inst : "=r" (reg) : : ); \
else \
__asm__(inst : "=r" (reg) : : ); \
return reg; \
}
#define MAKE_INTR_SET_REG_ZERO(isVolatile, name, inst, ...) \
ALWAYS_INLINE void __##name(void) \
{ \
if(isVolatile == 1) \
__asm__ volatile(inst : : "r" (0) : __VA_ARGS__); \
else \
__asm__(inst : : "r" (0) : __VA_ARGS__); \
}
#define MAKE_INTR_SET_REG(isVolatile, name, inst, ...) \
ALWAYS_INLINE void __##name(u32 reg) \
{ \
if(isVolatile == 1) \
__asm__ volatile(inst : : "r" (reg) : __VA_ARGS__); \
else \
__asm__(inst : : "r" (reg) : __VA_ARGS__); \
}
#define __bkpt(val) __asm__ volatile("bkpt #" #val : : : )
#if !__thumb__
// Program status register
MAKE_INTR_GET_REG(1, getCpsr, "mrs %0, cpsr")
MAKE_INTR_SET_REG(1, setCpsr_c, "msr cpsr_c, %0", "memory")
MAKE_INTR_SET_REG(1, setCpsr, "msr cpsr_cxsf, %0", "memory")
MAKE_INTR_GET_REG(1, getSpsr, "mrs %0, spsr")
MAKE_INTR_SET_REG(1, setSpsr_c, "msr spsr_c, %0", "memory")
MAKE_INTR_SET_REG(1, setSpsr, "msr spsr_cxsf, %0", "memory")
// Control Register
MAKE_INTR_GET_REG(1, getCr, "mrc p15, 0, %0, c1, c0, 0")
MAKE_INTR_SET_REG(1, setCr, "mcr p15, 0, %0, c1, c0, 0", "memory")
#endif // if !__thumb__
#ifdef ARM11
#define __cpsid(flags) __asm__ volatile("cpsid " #flags : : : "memory")
#define __cpsie(flags) __asm__ volatile("cpsie " #flags : : : "memory")
#define __setend(end) __asm__ volatile("setend " #end : : : "memory")
MAKE_INTR_NO_INOUT(1, nop)
MAKE_INTR_NO_INOUT(1, wfi, "memory")
MAKE_INTR_NO_INOUT(1, wfe, "memory")
MAKE_INTR_NO_INOUT(1, sev)
#if !__thumb__
ALWAYS_INLINE u8 __ldrexb(vu8 *addr)
{
u8 res;
__asm__ volatile("ldrexb %0, %1" : "=r" (res) : "Q" (*addr) : );
return res;
}
ALWAYS_INLINE u16 __ldrexh(vu16 *addr)
{
u16 res;
__asm__ volatile("ldrexh %0, %1" : "=r" (res) : "Q" (*addr) : );
return res;
}
ALWAYS_INLINE u32 __ldrex(vu32 *addr)
{
u32 res;
__asm__ volatile("ldrex %0, %1" : "=r" (res) : "Q" (*addr) : );
return res;
}
/*ALWAYS_INLINE u64 __ldrexd(vu64 *addr)
{
union
{
u32 r32[2];
u64 r64;
} r;
// TODO: "Error: even register required -- `ldrexd r3,r2,[r0]'"
#ifndef __ARMEB__ // Little endian
__asm__ volatile("ldrexd %0, %1, %2" : "=r" (r.r32[0]), "=r" (r.r32[1]) : "Q" (*addr) : );
#else // Big endian
__asm__ volatile("ldrexd %0, %1, %2" : "=r" (r.r32[1]), "=r" (r.r32[0]) : "Q" (*addr) : );
#endif
return r.r64;
}*/
ALWAYS_INLINE u32 __strexb(vu8 *addr, u8 val)
{
u32 res;
__asm__ volatile("strexb %0, %2, %1" : "=&r" (res), "=Q" (*addr) : "r" (val) : );
return res;
}
ALWAYS_INLINE u32 __strexh(vu16 *addr, u16 val)
{
u32 res;
__asm__ volatile("strexh %0, %2, %1" : "=&r" (res), "=Q" (*addr) : "r" (val) : );
return res;
}
ALWAYS_INLINE u32 __strex(vu32 *addr, u32 val)
{
u32 res;
__asm__ volatile("strex %0, %2, %1" : "=&r" (res), "=Q" (*addr) : "r" (val) : );
return res;
}
/*ALWAYS_INLINE u32 __strexd(vu64 *addr, u64 val)
{
union
{
u32 r32[2];
u64 r64;
} r;
r.r64 = val;
// TODO: "Error: even register required -- `strexd r0,r3,r2,[r1]'"
u32 res;
#ifndef __ARMEB__ // Little endian
__asm__ volatile("strexd %0, %2, %3, %1" : "=&r" (res), "=Q" (*addr) : "r" (r.r32[0]), "r" (r.r32[1]) : );
#else // Big endian
__asm__ volatile("strexd %0, %2, %3, %1" : "=&r" (res), "=Q" (*addr) : "r" (r.r32[1]), "r" (r.r32[0]) : );
#endif
return res;
}*/
MAKE_INTR_NO_INOUT(1, clrex, "memory")
// Debug ID Register
MAKE_INTR_GET_REG(0, getDidr, "mrc p14, 0, %0, c0, c0, 0")
// Debug Status and Control Register
MAKE_INTR_GET_REG(1, getDscr, "mrc p14, 0, %0, c0, c1, 0")
MAKE_INTR_SET_REG(1, setDscr, "mcr p14, 0, %0, c0, c1, 0", "memory")
// Data Transfer Register
// Vector Catch Register
MAKE_INTR_GET_REG(1, getVcr, "mrc p14, 0, %0, c0, c7, 0")
MAKE_INTR_SET_REG(1, setVcr, "mcr p14, 0, %0, c0, c7, 0", "memory")
// Breakpoint Value Register 0-5
MAKE_INTR_GET_REG(1, getBvr0, "mrc p14, 0, %0, c0, c0, 4")
MAKE_INTR_SET_REG(1, setBvr0, "mcr p14, 0, %0, c0, c0, 4", "memory")
MAKE_INTR_GET_REG(1, getBvr1, "mrc p14, 0, %0, c0, c1, 4")
MAKE_INTR_SET_REG(1, setBvr1, "mcr p14, 0, %0, c0, c1, 4", "memory")
MAKE_INTR_GET_REG(1, getBvr2, "mrc p14, 0, %0, c0, c2, 4")
MAKE_INTR_SET_REG(1, setBvr2, "mcr p14, 0, %0, c0, c2, 4", "memory")
MAKE_INTR_GET_REG(1, getBvr3, "mrc p14, 0, %0, c0, c3, 4")
MAKE_INTR_SET_REG(1, setBvr3, "mcr p14, 0, %0, c0, c3, 4", "memory")
MAKE_INTR_GET_REG(1, getBvr4, "mrc p14, 0, %0, c0, c4, 4")
MAKE_INTR_SET_REG(1, setBvr4, "mcr p14, 0, %0, c0, c4, 4", "memory")
MAKE_INTR_GET_REG(1, getBvr5, "mrc p14, 0, %0, c0, c5, 4")
MAKE_INTR_SET_REG(1, setBvr5, "mcr p14, 0, %0, c0, c5, 4", "memory")
// Breakpoint Control Register 0-5
MAKE_INTR_GET_REG(1, getBcr0, "mrc p14, 0, %0, c0, c0, 5")
MAKE_INTR_SET_REG(1, setBcr0, "mcr p14, 0, %0, c0, c0, 5", "memory")
MAKE_INTR_GET_REG(1, getBcr1, "mrc p14, 0, %0, c0, c1, 5")
MAKE_INTR_SET_REG(1, setBcr1, "mcr p14, 0, %0, c0, c1, 5", "memory")
MAKE_INTR_GET_REG(1, getBcr2, "mrc p14, 0, %0, c0, c2, 5")
MAKE_INTR_SET_REG(1, setBcr2, "mcr p14, 0, %0, c0, c2, 5", "memory")
MAKE_INTR_GET_REG(1, getBcr3, "mrc p14, 0, %0, c0, c3, 5")
MAKE_INTR_SET_REG(1, setBcr3, "mcr p14, 0, %0, c0, c3, 5", "memory")
MAKE_INTR_GET_REG(1, getBcr4, "mrc p14, 0, %0, c0, c4, 5")
MAKE_INTR_SET_REG(1, setBcr4, "mcr p14, 0, %0, c0, c4, 5", "memory")
MAKE_INTR_GET_REG(1, getBcr5, "mrc p14, 0, %0, c0, c5, 5")
MAKE_INTR_SET_REG(1, setBcr5, "mcr p14, 0, %0, c0, c5, 5", "memory")
// Watchpoint Value Register 0-1
MAKE_INTR_GET_REG(1, getWvr0, "mrc p14, 0, %0, c0, c0, 6")
MAKE_INTR_SET_REG(1, setWvr0, "mcr p14, 0, %0, c0, c0, 6", "memory")
MAKE_INTR_GET_REG(1, getWvr1, "mrc p14, 0, %0, c0, c1, 6")
MAKE_INTR_SET_REG(1, setWvr1, "mcr p14, 0, %0, c0, c1, 6", "memory")
// Watchpoint Control Register 0-1
MAKE_INTR_GET_REG(1, getWcr0, "mrc p14, 0, %0, c0, c0, 7")
MAKE_INTR_SET_REG(1, setWcr0, "mcr p14, 0, %0, c0, c0, 7", "memory")
MAKE_INTR_GET_REG(1, getWcr1, "mrc p14, 0, %0, c0, c1, 7")
MAKE_INTR_SET_REG(1, setWcr1, "mcr p14, 0, %0, c0, c1, 7", "memory")
ALWAYS_INLINE u32 __getCpuId(void)
{
u32 cpuId;
__asm__("mrc p15, 0, %0, c0, c0, 5" : "=r" (cpuId) : );
return cpuId & 3;
}
// Auxiliary Control Register
MAKE_INTR_GET_REG(1, getAcr, "mrc p15, 0, %0, c1, c0, 1")
MAKE_INTR_SET_REG(1, setAcr, "mcr p15, 0, %0, c1, c0, 1", "memory")
// Translation Table Base Register 0
MAKE_INTR_GET_REG(1, getTtbr0, "mrc p15, 0, %0, c2, c0, 0")
MAKE_INTR_SET_REG(1, setTtbr0, "mcr p15, 0, %0, c2, c0, 0", "memory")
// Translation Table Base Register 1
MAKE_INTR_GET_REG(1, getTtbr1, "mrc p15, 0, %0, c2, c0, 1")
MAKE_INTR_SET_REG(1, setTtbr1, "mcr p15, 0, %0, c2, c0, 1", "memory")
// Translation Table Base Control Register
MAKE_INTR_GET_REG(1, getTtbcr, "mrc p15, 0, %0, c2, c0, 2")
MAKE_INTR_SET_REG(1, setTtbcr, "mcr p15, 0, %0, c2, c0, 2", "memory")
// Domain Access Control Register
MAKE_INTR_GET_REG(1, getDacr, "mrc p15, 0, %0, c3, c0, 0")
MAKE_INTR_SET_REG(1, setDacr, "mcr p15, 0, %0, c3, c0, 0", "memory")
// Data Fault Status Register
MAKE_INTR_GET_REG(1, getDfsr, "mrc p15, 0, %0, c5, c0, 0")
MAKE_INTR_SET_REG(1, setDfsr, "mcr p15, 0, %0, c5, c0, 0", "memory")
// Instruction Fault Status Register
MAKE_INTR_GET_REG(1, getIfsr, "mrc p15, 0, %0, c5, c0, 1")
MAKE_INTR_SET_REG(1, setIfsr, "mcr p15, 0, %0, c5, c0, 1", "memory")
// Fault Address Register
MAKE_INTR_GET_REG(1, getFar, "mrc p15, 0, %0, c6, c0, 0")
MAKE_INTR_SET_REG(1, setFar, "mcr p15, 0, %0, c6, c0, 0", "memory")
// Watchpoint Fault Address Register
MAKE_INTR_GET_REG(1, getWfar, "mrc p15, 0, %0, c6, c0, 1")
MAKE_INTR_SET_REG(1, setWfar, "mcr p15, 0, %0, c6, c0, 1", "memory")
// Flush Prefetch Buffer
// Data Synchronization Barrier
// Data Memory Barrier
MAKE_INTR_SET_REG_ZERO(1, isb, "mcr p15, 0, %0, c7, c5, 4", "memory")
MAKE_INTR_SET_REG_ZERO(1, dsb, "mcr p15, 0, %0, c7, c10, 4", "memory")
MAKE_INTR_SET_REG_ZERO(1, dmb, "mcr p15, 0, %0, c7, c10, 5", "memory")
// FCSE PID Register
MAKE_INTR_GET_REG(1, getFcsepidr, "mrc p15, 0, %0, c13, c0, 0")
MAKE_INTR_SET_REG(1, setFcsepidr, "mcr p15, 0, %0, c13, c0, 0", "memory")
// Context ID Register
MAKE_INTR_GET_REG(1, getCidr, "mrc p15, 0, %0, c13, c0, 1")
MAKE_INTR_SET_REG(1, setCidr, "mcr p15, 0, %0, c13, c0, 1", "memory")
#endif // if !__thumb__
#elif ARM9
#if !__thumb__
MAKE_INTR_SET_REG_ZERO(1, wfi, "mcr p15, 0, %0, c7, c0, 4", "memory")
#endif // if !__thumb__
#endif // ifdef ARM11
#undef MAKE_INTR_NO_INOUT
#undef MAKE_INTR_GET_REG
#undef MAKE_INTR_SET_REG_ZERO
#undef MAKE_INTR_SET_REG
#endif // if !__ASSEMBLER__

View File

@ -0,0 +1,47 @@
/**
* @file vram.h
* @brief VRAM allocator.
*/
#pragma once
/**
* @brief Allocates a 0x80-byte aligned buffer.
* @param size Size of the buffer to allocate.
* @return The allocated buffer.
*/
void* vramAlloc(size_t size);
/**
* @brief Allocates a buffer aligned to the given size.
* @param size Size of the buffer to allocate.
* @param alignment Alignment to use.
* @return The allocated buffer.
*/
void* vramMemAlign(size_t size, size_t alignment);
/**
* @brief Reallocates a buffer.
* Note: Not implemented yet.
* @param mem Buffer to reallocate.
* @param size Size of the buffer to allocate.
* @return The reallocated buffer.
*/
void* vramRealloc(void* mem, size_t size);
/**
* @brief Retrieves the allocated size of a buffer.
* @return The size of the buffer.
*/
size_t vramGetSize(void* mem);
/**
* @brief Frees a buffer.
* @param mem Buffer to free.
*/
void vramFree(void* mem);
/**
* @brief Gets the current VRAM free space.
* @return The current VRAM free space.
*/
u32 vramSpaceFree(void);

View File

@ -1,89 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2024 profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#ifdef __cplusplus
extern "C"
{
#endif
typedef struct
{
u16 magic; // "BM"
u32 fileSize;
u16 reserved;
u16 reserved2;
u32 pixelOffset; // From file start.
} PACKED BmpHeader;
static_assert(sizeof(BmpHeader) == 14);
typedef enum
{
BI_RGB = 0u,
BI_RLE8 = 1u, // 8 bit per pixel only.
BI_RLE4 = 2u, // 4 bit per pixel only.
BI_BITFIELDS = 3u, // BitmapV2Infoheader RGB masks, BitmapV3Infoheader+ RGBA masks.
BI_JPEG = 4u, // BitmapV4Infoheader+.
BI_PNG = 5u, // BitmapV4Infoheader+.
BI_CMYK = 11u, // Only Windows Metafile (WMF) CMYK.
BI_CMYKRLE8 = 12u, // Only Windows Metafile (WMF) CMYK.
BI_CMYKRLE4 = 13u // Only Windows Metafile (WMF) CMYK.
} BitmapCompr;
typedef struct
{
u32 headerSize; // Size of this header. 40 bytes.
s32 width;
s32 height; // If >=0, pixel lines are in order bottom to top. Otherwise top to bottom.
u16 colorPlanes; // Must be 1.
u16 bitsPerPixel; // 1, 4, 8, 16, 24, 32.
u32 compression; // See BitmapCompr enum.
u32 imageSize; // Can be 0 if compression is BI_RGB.
s32 xPixelsPerMeter;
s32 yPixelsPerMeter;
u32 colorsUsed;
u32 colorsImportant;
} PACKED Bitmapinfoheader;
static_assert(sizeof(Bitmapinfoheader) == 0x28);
typedef struct
{
BmpHeader header;
Bitmapinfoheader dib;
} PACKED BmpV1;
static_assert(sizeof(BmpV1) == 0x36);
// Note: Technically this is BMP V2 but we use the shorter Bitmapinfoheader (V1).
// The color masks are only needed for compression BI_BITFIELDS.
typedef struct
{
BmpHeader header;
Bitmapinfoheader dib;
u32 rMask;
u32 gMask;
u32 bMask;
} PACKED BmpV1WithMasks;
static_assert(sizeof(BmpV1WithMasks) == 0x42);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -1,76 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2024 profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#include "oaf_error_codes.h"
#ifdef __cplusplus
extern "C"
{
#endif
#define OAF_WORK_DIR "sdmc:/3ds/open_agb_firm"
#define OAF_SAVE_DIR "saves" // Relative to work dir.
#define OAF_SCREENSHOT_DIR "screenshots" // Relative to work dir.
typedef struct
{
// [general]
u8 backlight; // Both LCDs.
u8 backlightSteps;
bool directBoot;
bool useGbaDb;
bool useSavesFolder;
// [video]
u8 scaler; // 0 = 1:1/none, 1 = bilinear (GPU) x1.5, 2 = matrix (hardware) x1.5.
u8 colorProfile; // 0 = none, 1 = GBA, 2 = GB micro, 3 = GBA SP (AGS-101), 4 = DS phat, 5 = DS lite, 6 = Nintendo Switch Online, 7 = Visual Boy Advance/No$GBA, 8 = identity.
float contrast; // Range 0.0-1.0.
float brightness; // Range 0.0-1.0.
float saturation; // Range 0.0-1.0.
// [audio]
u8 audioOut; // 0 = auto, 1 = speakers, 2 = headphones.
s8 volume; // -128 = muted, -127 - 48 = -63.5 - +24 dB.
// Higher than 48 = volume control via slider.
// [input]
u32 buttonMaps[10]; // A, B, Select, Start, Right, Left, Up, Down, R, L.
// [game]
u8 saveSlot;
u8 saveType;
// [advanced]
bool saveOverride;
u16 defaultSave; // TODO: Should be u8. Investigate if u8 has any downsides.
} OafConfig;
extern OafConfig g_oafConfig; // Global config in config.c.
Result parseOafConfig(const char *const path, OafConfig *cfg, const bool newCfgOnError);
#ifdef __cplusplus
} // extern "C"
#endif

192
include/arm11/console.h Normal file
View File

@ -0,0 +1,192 @@
#pragma once
/*
* This code is part of ctrulib (https://github.com/smealum/ctrulib)
*/
/**
* @file console.h
* @brief 3ds stdio support.
*
* Provides stdio integration for printing to the 3DS screen as well as debug print
* functionality provided by stderr.
*
* General usage is to initialize the console by:
* @code
* consoleDemoInit()
* @endcode
* or to customize the console usage by:
* @code
* consoleInit()
* @endcode
*/
#include "types.h"
#include "hardware/gfx.h"
#ifdef __cplusplus
extern "C" {
#endif
#define CONSOLE_ESC(x) "\x1b[" #x
#define CONSOLE_RESET CONSOLE_ESC(0m)
#define CONSOLE_BLACK CONSOLE_ESC(30m)
#define CONSOLE_RED CONSOLE_ESC(31;1m)
#define CONSOLE_GREEN CONSOLE_ESC(32;1m)
#define CONSOLE_YELLOW CONSOLE_ESC(33;1m)
#define CONSOLE_BLUE CONSOLE_ESC(34;1m)
#define CONSOLE_MAGENTA CONSOLE_ESC(35;1m)
#define CONSOLE_CYAN CONSOLE_ESC(36;1m)
#define CONSOLE_WHITE CONSOLE_ESC(37;1m)
/// A callback for printing a character.
typedef bool(*ConsolePrint)(void* con, int c);
/// A font struct for the console.
typedef struct ConsoleFont
{
const u8* gfx; ///< A pointer to the font graphics
u16 asciiOffset; ///< Offset to the first valid character in the font table
u16 numChars; ///< Number of characters in the font graphics
}ConsoleFont;
/**
* @brief Console structure used to store the state of a console render context.
*
* Default values from consoleGetDefault();
* @code
* PrintConsole defaultConsole =
* {
* //Font:
* {
* (u8*)default_font_bin, //font gfx
* 0, //first ascii character in the set
* 128, //number of characters in the font set
* },
* 0,0, //cursorX cursorY
* 0,0, //prevcursorX prevcursorY
* 40, //console width
* 30, //console height
* 0, //window x
* 0, //window y
* 32, //window width
* 24, //window height
* 3, //tab size
* 0, //font character offset
* 0, //print callback
* false //console initialized
* };
* @endcode
*/
typedef struct PrintConsole
{
ConsoleFont font; ///< Font of the console
u16 *frameBuffer; ///< Framebuffer address
int cursorX; ///< Current X location of the cursor (as a tile offset by default)
int cursorY; ///< Current Y location of the cursor (as a tile offset by default)
int prevCursorX; ///< Internal state
int prevCursorY; ///< Internal state
int consoleWidth; ///< Width of the console hardware layer in characters
int consoleHeight; ///< Height of the console hardware layer in characters
int windowX; ///< Window X location in characters (not implemented)
int windowY; ///< Window Y location in characters (not implemented)
int windowWidth; ///< Window width in characters (not implemented)
int windowHeight; ///< Window height in characters (not implemented)
int tabSize; ///< Size of a tab
int fg; ///< Foreground color
int bg; ///< Background color
int flags; ///< Reverse/bright flags
ConsolePrint PrintChar; ///< Callback for printing a character. Should return true if it has handled rendering the graphics (else the print engine will attempt to render via tiles).
bool consoleInitialised; ///< True if the console is initialized
}PrintConsole;
#define CONSOLE_COLOR_BOLD (1<<0) ///< Bold text
#define CONSOLE_COLOR_FAINT (1<<1) ///< Faint text
#define CONSOLE_ITALIC (1<<2) ///< Italic text
#define CONSOLE_UNDERLINE (1<<3) ///< Underlined text
#define CONSOLE_BLINK_SLOW (1<<4) ///< Slow blinking text
#define CONSOLE_BLINK_FAST (1<<5) ///< Fast blinking text
#define CONSOLE_COLOR_REVERSE (1<<6) ///< Reversed color text
#define CONSOLE_CONCEAL (1<<7) ///< Concealed text
#define CONSOLE_CROSSED_OUT (1<<8) ///< Crossed out text
/// Console debug devices supported by libnds.
typedef enum {
debugDevice_NULL, ///< Swallows prints to stderr
debugDevice_3DMOO, ///< Directs stderr debug statements to 3dmoo
debugDevice_CONSOLE, ///< Directs stderr debug statements to 3DS console window
} debugDevice;
/**
* @brief Loads the font into the console.
* @param console Pointer to the console to update, if NULL it will update the current console.
* @param font The font to load.
*/
void consoleSetFont(PrintConsole* console, ConsoleFont* font);
/**
* @brief Sets the print window.
* @param console Console to set, if NULL it will set the current console window.
* @param x X location of the window.
* @param y Y location of the window.
* @param width Width of the window.
* @param height Height of the window.
*/
void consoleSetWindow(PrintConsole* console, int x, int y, int width, int height);
/**
* @brief Gets a pointer to the console with the default values.
* This should only be used when using a single console or without changing the console that is returned, otherwise use consoleInit().
* @return A pointer to the console with the default values.
*/
PrintConsole* consoleGetDefault(void);
/**
* @brief Make the specified console the render target.
* @param console A pointer to the console struct (must have been initialized with consoleInit(PrintConsole* console)).
* @return A pointer to the previous console.
*/
PrintConsole *consoleSelect(PrintConsole* console);
/**
* @brief Returns the currently used console.
* @return A pointer to the current console.
*/
PrintConsole *consoleGet(void);
/**
* @brief Returns the currently used foreground color.
* @return The foreground color in RGB565.
*/
u16 consoleGetFgColor(void);
/**
* @brief Initialise the console.
* @param screen The screen to use for the console.
* @param console A pointer to the console data to initialize (if it's NULL, the default console will be used).
* @return A pointer to the current console.
*/
PrintConsole* consoleInit(u8 screen, PrintConsole* console);
/// Clears the screan by using iprintf("\x1b[2J");
void consoleClear(void);
void consoleSetCursor(PrintConsole* console, int x, int y);
void drawConsoleWindow(PrintConsole* console, int thickness, u8 colorIndex);
u16 consoleGetRGB565Color(u8 colorIndex);
ssize_t con_write(UNUSED struct _reent *r,UNUSED void *fd,const char *ptr, size_t len);
#ifdef __cplusplus
}
#endif

50
include/arm11/debug.h Normal file
View File

@ -0,0 +1,50 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
noreturn void panic(void);
noreturn void panicMsg(const char *msg);
// Exception tests
/*static inline regTest(void)
{
__asm__ volatile("mov r0, #1\n\tmov r1, #2\n\tmov r2, #3\n\tmov r3, #4\n\tmov r4, #5\n\t"
"mov r5, #6\n\tmov r6, #7\n\tmov r7, #8\n\tmov r8, #9\n\tmov r9, #10\n\t"
"mov r10, #11\n\tmov r11, #12\n\tmov r12, #13\n\tmov r13, #14\n\t"
"mov r14, #15\n\tmov r15, #16\n\t" : :);
}
static inline breakpointTest(void)
{
__asm__ volatile("bkpt #0xCAFE" : :);
}
static inline dataAbortTest(void)
{
__asm__ volatile("mov r0, #4\n\tmov r1, #0xEF\n\tstr r1, [r0]" : :);
}
static inline undefInstrTest(void)
{
__asm__ volatile("udf #0xDEAD" : :);
}*/

View File

@ -1,34 +1,7 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "error_codes.h"
#ifdef __cplusplus
extern "C"
{
#endif
Result browseFiles(const char *const basePath, char selected[512]);
#ifdef __cplusplus
} // extern "C"
#endif

48
include/arm11/fmt.h Normal file
View File

@ -0,0 +1,48 @@
#pragma once
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#include <stdarg.h>
#include "types.h"
u32 ee_vsnprintf(char *const buf, u32 size, const char *const fmt, va_list arg);
u32 ee_vsprintf(char *const buf, const char *const fmt, va_list arg);
__attribute__ ((format (printf, 2, 3))) u32 ee_sprintf(char *const buf, const char *const fmt, ...);
__attribute__ ((format (printf, 3, 4))) u32 ee_snprintf(char *const buf, u32 size, const char *const fmt, ...);
__attribute__ ((format (printf, 1, 2))) u32 ee_printf(const char *const fmt, ...);
u32 ee_puts(const char *const str);
#ifdef NDEBUG
#define debug_printf(fmt, ...) ((void)0)
#define debug_puts(str) ((void)0)
#else
#define debug_printf(fmt, ...) ee_printf(fmt, ##__VA_ARGS__)
#define debug_puts(str) ee_puts(str)
#endif

3082
include/arm11/font_6x10.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,73 @@
#pragma once
#include <assert.h>
#include "types.h"
// Temporary define for all incomplete entries.
#define UNSPECIFIED 0xFF
typedef struct
{
char gameCode[3]; // Without the region letter.
u8 type;
} SaveTypeLut;
static_assert(offsetof(SaveTypeLut, type) == 3, "Error: Member 'type' of SaveTypeLut is not at offset 3!");
/*
* 0x0 = 16 MiB or smaller ROM + EEPROM 4k/8k (512/1024 bytes)
* 0x1 = 32 MiB ROM + EEPROM 4k/8k (512/1024 bytes)
* 0x2 = 16 MiB or smaller ROM + EEPROM 64k (8 KiB)
* 0x3 = 32 MiB ROM + EEPROM 64k (8 KiB)
* 0x4 = Flash 512k (64 KiB) with RTC, ID=0x3D1F, Atmel
* 0x5 = Flash 512k (64 KiB) without RTC, ID=0x3D1F, Atmel
* 0x6 = Flash 512k (64 KiB) with RTC, ID=0xD4BF, SST
* 0x7 = Flash 512k (64 KiB) without RTC, ID=0xD4BF, SST
* 0x8 = Flash 512k (64 KiB) with RTC, ID=0x1B32, Panasonic
* 0x9 = Flash 512k (64 KiB) without RTC, ID=0x1B32, Panasonic
* 0xA = Flash 1M (128 KiB) with RTC, ID=0x09C2, Macronix
* 0xB = Flash 1M (128 KiB) without RTC, ID=0x09C2, Macronix
* 0xC = Flash 1M (128 KiB) with RTC, ID=0x1362, Sanyo
* 0xD = Flash 1M (128 KiB) without RTC, ID=0x1362, Sanyo
* 0xE = SRAM/FRAM/FeRAM 256k (32 KiB)
* 0xF = No save chip
*/
/*
* [] = Optional
* <> = Required
*
* Format:
* // [SDK save string if any]
* // <no-intro game release names sepearated by newlines>
* {"<game code without region (last letter)>", <save type>},
*
* All entries ordered by release number.
*/
alignas(4) static const SaveTypeLut saveTypeLut[] =
{
// EEPROM_V120
// 0002 - Super Mario Advance - Super Mario USA + Mario Brothers (Japan)
// 0049 - Super Mario Advance (USA, Europe)
// 1570 - Chaoji Maliou 2 (China)
// x116 - Super Mario Advance (USA, Europe) (Wii U Virtual Console)
{"AMA", 0x0},
// EEPROM_V122
// 0237 - Super Mario Advance 2 - Super Mario World + Mario Brothers (Japan)
// 0288 - Super Mario Advance 2 - Super Mario World (USA, Australia)
// 0389 - Super Mario Advance 2 - Super Mario World (Europe) (En,Fr,De,Es)
// 2328 - Chaoji Maliou Shijie (China)
{"AA2", 0x2},
// EEPROM_V122
// 0578 - Super Mario Advance 3 - Yoshi's Island (USA)
// 0580 - Super Mario Advance 3 - Yoshi's Island + Mario Brothers (Japan)
// 0608 - Super Mario Advance 3 - Yoshi's Island (Europe) (En,Fr,De,Es,It)
// 2299 - Yaoxi Dao (China)
// x115 - Super Mario Advance 3 - Yoshi's Island (USA) (Wii U Virtual Console)
// x161 - Super Mario Advance 3 - Yoshi's Island (Europe) (En,Fr,De,Es,It) (Wii U Virtual Console)
{"A3A", 0x2},
};

View File

@ -1,45 +1,289 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#ifdef __cplusplus
extern "C"
// 360x240, no filter.
alignas(16) static const u8 gbaGpuInitList[1136] =
{
#endif
0x01, 0x00, 0x00, 0x00, 0x10, 0x01, 0x0F, 0x00, 0x00, 0x00, 0x06, 0x03,
0x1C, 0x01, 0x2F, 0x80, 0x00, 0x00, 0x03, 0x03, 0xF0, 0xF0, 0x18, 0x01,
0xF0, 0xF0, 0x18, 0x01, 0x6E, 0x00, 0x0F, 0x00, 0x03, 0x00, 0x00, 0x00,
0x16, 0x01, 0x0F, 0x00, 0x01, 0x00, 0x01, 0x00, 0x17, 0x01, 0x0F, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1B, 0x01, 0x0F, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x12, 0x01, 0x3F, 0x80, 0x0F, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x45, 0x00,
0x41, 0x00, 0x3F, 0x80, 0x10, 0x11, 0x11, 0x38, 0x00, 0x90, 0x46, 0x00,
0x14, 0xAE, 0x47, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x68, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x00, 0x2F, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x29, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x02, 0x03, 0x00,
0x00, 0x00, 0x00, 0x00, 0x44, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0xCB, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x4E, 0xCC, 0x02, 0x7F, 0x00,
0x01, 0xF0, 0x07, 0x4E, 0x02, 0x08, 0x02, 0x08, 0x03, 0x18, 0x02, 0x08,
0x04, 0x28, 0x02, 0x08, 0x05, 0x38, 0x02, 0x08, 0x06, 0x10, 0x20, 0x4C,
0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0xBF, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, 0x02, 0x0F, 0x00,
0x6E, 0x03, 0x00, 0x00, 0xD6, 0x02, 0x6F, 0x00, 0xA1, 0x0A, 0x00, 0x00,
0x68, 0xC3, 0x06, 0x00, 0x64, 0xC3, 0x06, 0x00, 0x62, 0xC3, 0x06, 0x00,
0x61, 0xC3, 0x06, 0x00, 0x6F, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x7F,
0xBA, 0x02, 0x0F, 0x00, 0x03, 0x00, 0x00, 0x00, 0xBD, 0x02, 0x0F, 0x00,
0x01, 0x00, 0x00, 0x00, 0x4A, 0x02, 0x0F, 0x00, 0x01, 0x00, 0x00, 0x00,
0x51, 0x02, 0x0F, 0x00, 0x01, 0x00, 0x00, 0x00, 0x5E, 0x02, 0x01, 0x00,
0x02, 0x00, 0x00, 0x00, 0x4F, 0x00, 0x7F, 0x80, 0x00, 0x01, 0x02, 0x03,
0x0C, 0x0D, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x64, 0x00, 0x0F, 0x00,
0x01, 0x01, 0x00, 0x00, 0x6F, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00,
0x29, 0x02, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x02, 0x0F, 0x00,
0x00, 0x00, 0x00, 0x00, 0x54, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xA0,
0x89, 0x02, 0x0F, 0x00, 0x7B, 0x00, 0x00, 0x00, 0x01, 0x02, 0x1F, 0x80,
0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xA0,
0xB9, 0x02, 0x0B, 0x00, 0x01, 0x00, 0x00, 0x00, 0x42, 0x02, 0x0F, 0x00,
0x10, 0x00, 0x00, 0x00, 0xBB, 0x02, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x6D, 0x00, 0x0F, 0x00,
0x02, 0x00, 0x00, 0x00, 0x40, 0x00, 0x0F, 0x00, 0x00, 0x00, 0xBF, 0x00,
0x4D, 0x00, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x04, 0x01, 0x3F, 0x80, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x10, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x26, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x01, 0x0F, 0x00, 0x00, 0x00, 0x76, 0x76, 0x01, 0x01, 0x0F, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x0F, 0x00, 0x00, 0x01, 0xE4, 0x00,
0x00, 0x01, 0x07, 0x00, 0x00, 0x3C, 0x00, 0x80, 0x30, 0x01, 0x0F, 0x00,
0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x18, 0x01, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x6A, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
0x81, 0x00, 0x4F, 0x80, 0x00, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x01, 0x00, 0x00, 0x00, // Last 4 bytes: Texture format.
0x8E, 0x00, 0x0F, 0x00, 0x01, 0x10, 0x01, 0x00, 0x80, 0x00, 0x0B, 0x00,
0x00, 0x00, 0x01, 0x00, 0x80, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00,
0x8B, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x07, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00,
0xE1, 0x00, 0x0F, 0x00, 0x03, 0x00, 0x03, 0x00, 0xC0, 0x00, 0x4F, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0xC8, 0x00, 0x4F, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0xD0, 0x00, 0x4F, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0xD8, 0x00, 0x4F, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0xF0, 0x00, 0x4F, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0xF8, 0x00, 0x4F, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, 0xC0, 0x02, 0x3F, 0x80,
0xBF, 0x00, 0x00, 0x3E, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0x02, 0x0F, 0x00,
0x00, 0x00, 0x80, 0xBF, 0xC1, 0x02, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
0x88, 0x88, 0x08, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0xD7, 0xA3, 0xBB,
0x00, 0x00, 0x80, 0xBF, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0x7F, 0xB0, 0x02, 0x0F, 0x00, 0x00, 0x01, 0x00, 0x00,
0x5E, 0x02, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x5F, 0x02, 0x0F, 0x00,
0x00, 0x00, 0x00, 0x80, 0x27, 0x02, 0x0F, 0x00, 0x01, 0x00, 0x00, 0x00,
0x53, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x02, 0x01, 0x00,
0x0F, 0x00, 0x00, 0x00, 0x32, 0x02, 0x0F, 0x00, 0x3E, 0x00, 0x00, 0x3F,
0x33, 0x02, 0x2F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x43, 0x00,
0x00, 0x00, 0x00, 0x00, 0x33, 0x02, 0x2F, 0x80, 0x10, 0x3E, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x3F, 0x33, 0x02, 0x2F, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x02, 0x2F, 0x80, 0x10, 0x3E, 0x00, 0x00, 0x00, 0x68, 0x3E, 0x00,
0x3E, 0x00, 0x00, 0x3F, 0x33, 0x02, 0x2F, 0x80, 0xE0, 0x46, 0x00, 0x00,
0x00, 0x40, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x02, 0x2F, 0x80,
0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x3F,
0x33, 0x02, 0x2F, 0x80, 0xE0, 0x46, 0x00, 0x00, 0x00, 0x7C, 0x47, 0x00,
0x00, 0x00, 0x00, 0x00, 0x33, 0x02, 0x2F, 0x80, 0x00, 0x3F, 0x00, 0x00,
0x00, 0x68, 0x3E, 0x00, 0x01, 0x00, 0x00, 0x00, 0x45, 0x02, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x53, 0x02, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
0x31, 0x02, 0x0F, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x01, 0x0F, 0x00,
0x01, 0x00, 0x00, 0x00, 0x10, 0x01, 0x0F, 0x00, 0x01, 0x00, 0x00, 0x00,
0x63, 0x00, 0x0F, 0x00, 0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x0F, 0x00,
0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x0F, 0x00
};
// 240x160 with bilinear scaling, no filter.
/*alignas(16) static const u8 gbaGpuInitList[1136] =
{
0x01, 0x00, 0x00, 0x00, 0x10, 0x01, 0x0F, 0x00, 0x00, 0x00, 0x06, 0x03,
0x1C, 0x01, 0x2F, 0x80, 0x00, 0x00, 0x03, 0x03, 0xF0, 0xF0, 0x18, 0x01,
0xF0, 0xF0, 0x18, 0x01, 0x6E, 0x00, 0x0F, 0x00, 0x03, 0x00, 0x00, 0x00,
0x16, 0x01, 0x0F, 0x00, 0x01, 0x00, 0x01, 0x00, 0x17, 0x01, 0x0F, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1B, 0x01, 0x0F, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x12, 0x01, 0x3F, 0x80, 0x0F, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x45, 0x00,
0x41, 0x00, 0x3F, 0x80, 0x10, 0x11, 0x11, 0x38, 0x00, 0x90, 0x46, 0x00,
0x14, 0xAE, 0x47, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x68, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x00, 0x2F, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x29, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x02, 0x03, 0x00,
0x00, 0x00, 0x00, 0x00, 0x44, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0xCB, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x4E, 0xCC, 0x02, 0x7F, 0x00,
0x01, 0xF0, 0x07, 0x4E, 0x02, 0x08, 0x02, 0x08, 0x03, 0x18, 0x02, 0x08,
0x04, 0x28, 0x02, 0x08, 0x05, 0x38, 0x02, 0x08, 0x06, 0x10, 0x20, 0x4C,
0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0xBF, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, 0x02, 0x0F, 0x00,
0x6E, 0x03, 0x00, 0x00, 0xD6, 0x02, 0x6F, 0x00, 0xA1, 0x0A, 0x00, 0x00,
0x68, 0xC3, 0x06, 0x00, 0x64, 0xC3, 0x06, 0x00, 0x62, 0xC3, 0x06, 0x00,
0x61, 0xC3, 0x06, 0x00, 0x6F, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x7F,
0xBA, 0x02, 0x0F, 0x00, 0x03, 0x00, 0x00, 0x00, 0xBD, 0x02, 0x0F, 0x00,
0x01, 0x00, 0x00, 0x00, 0x4A, 0x02, 0x0F, 0x00, 0x01, 0x00, 0x00, 0x00,
0x51, 0x02, 0x0F, 0x00, 0x01, 0x00, 0x00, 0x00, 0x5E, 0x02, 0x01, 0x00,
0x02, 0x00, 0x00, 0x00, 0x4F, 0x00, 0x7F, 0x80, 0x00, 0x01, 0x02, 0x03,
0x0C, 0x0D, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x64, 0x00, 0x0F, 0x00,
0x01, 0x01, 0x00, 0x00, 0x6F, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00,
0x29, 0x02, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x02, 0x0F, 0x00,
0x00, 0x00, 0x00, 0x00, 0x54, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xA0,
0x89, 0x02, 0x0F, 0x00, 0x7B, 0x00, 0x00, 0x00, 0x01, 0x02, 0x1F, 0x80,
0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xA0,
0xB9, 0x02, 0x0B, 0x00, 0x01, 0x00, 0x00, 0x00, 0x42, 0x02, 0x0F, 0x00,
0x10, 0x00, 0x00, 0x00, 0xBB, 0x02, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x6D, 0x00, 0x0F, 0x00,
0x02, 0x00, 0x00, 0x00, 0x40, 0x00, 0x0F, 0x00, 0x00, 0x00, 0xBF, 0x00,
0x4D, 0x00, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x04, 0x01, 0x3F, 0x80, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x10, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x26, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x01, 0x0F, 0x00, 0x00, 0x00, 0x76, 0x76, 0x01, 0x01, 0x0F, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x0F, 0x00, 0x00, 0x01, 0xE4, 0x00,
0x00, 0x01, 0x07, 0x00, 0x00, 0x3C, 0x00, 0x80, 0x30, 0x01, 0x0F, 0x00,
0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x18, 0x01, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x6A, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
0x81, 0x00, 0x4F, 0x80, 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x01, 0x00, 0x00, 0x00,
0x8E, 0x00, 0x0F, 0x00, 0x01, 0x10, 0x01, 0x00, 0x80, 0x00, 0x0B, 0x00,
0x00, 0x00, 0x01, 0x00, 0x80, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00,
0x8B, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x07, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00,
0xE1, 0x00, 0x0F, 0x00, 0x03, 0x00, 0x03, 0x00, 0xC0, 0x00, 0x4F, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0xC8, 0x00, 0x4F, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0xD0, 0x00, 0x4F, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0xD8, 0x00, 0x4F, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0xF0, 0x00, 0x4F, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0xF8, 0x00, 0x4F, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, 0xC0, 0x02, 0x3F, 0x80,
0xBF, 0x00, 0x00, 0x3E, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0x02, 0x0F, 0x00,
0x00, 0x00, 0x80, 0xBF, 0xC1, 0x02, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
0x88, 0x88, 0x08, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0xD7, 0xA3, 0xBB,
0x00, 0x00, 0x80, 0xBF, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0x7F, 0xB0, 0x02, 0x0F, 0x00, 0x00, 0x01, 0x00, 0x00,
0x5E, 0x02, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x5F, 0x02, 0x0F, 0x00,
0x00, 0x00, 0x00, 0x80, 0x27, 0x02, 0x0F, 0x00, 0x01, 0x00, 0x00, 0x00,
0x53, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x02, 0x01, 0x00,
0x0F, 0x00, 0x00, 0x00, 0x32, 0x02, 0x0F, 0x00, 0x3E, 0x00, 0x00, 0x3F,
0x33, 0x02, 0x2F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x43, 0x00,
0x00, 0x00, 0x00, 0x00, 0x33, 0x02, 0x2F, 0x80, 0x80, 0x3D, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x3F, 0x33, 0x02, 0x2F, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x02, 0x2F, 0x80, 0x80, 0x3D, 0x00, 0x00, 0x00, 0xE0, 0x3E, 0x00,
0x3E, 0x00, 0x00, 0x3F, 0x33, 0x02, 0x2F, 0x80, 0xE0, 0x46, 0x00, 0x00,
0x00, 0x40, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x02, 0x2F, 0x80,
0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x3F,
0x33, 0x02, 0x2F, 0x80, 0xE0, 0x46, 0x00, 0x00, 0x00, 0x7C, 0x47, 0x00,
0x00, 0x00, 0x00, 0x00, 0x33, 0x02, 0x2F, 0x80, 0x00, 0x3F, 0x00, 0x00,
0x00, 0xE0, 0x3E, 0x00, 0x01, 0x00, 0x00, 0x00, 0x45, 0x02, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x53, 0x02, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
0x31, 0x02, 0x0F, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x01, 0x0F, 0x00,
0x01, 0x00, 0x00, 0x00, 0x10, 0x01, 0x0F, 0x00, 0x01, 0x00, 0x00, 0x00,
0x63, 0x00, 0x0F, 0x00, 0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x0F, 0x00,
0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x0F, 0x00
};*/
#define GPU_RENDER_BUF_ADDR (0x18180000)
#define GPU_TEXTURE_ADDR (0x18200000)
#define GPU_TEXTURE2_ADDR (0x18300000)
#define GBA_INIT_LIST_SIZE (1136)
#define GBA_LIST2_SIZE (448)
extern u8 gbaGpuInitList[GBA_INIT_LIST_SIZE];
extern u8 gbaGpuList2[GBA_LIST2_SIZE];
void patchGbaGpuCmdList(const u8 scaleType, const bool useSecondTexture);
#ifdef __cplusplus
} // extern "C"
#endif
// 360x240, no filter.
alignas(16) static const u8 gbaGpuList2[448] =
{
0x01, 0x00, 0x00, 0x00, 0x10, 0x01, 0x0F, 0x00, 0x00, 0x00, 0x06, 0x03,
0x1C, 0x01, 0x2F, 0x80, 0x00, 0x00, 0x03, 0x03, 0xF0, 0xF0, 0x18, 0x01,
0xF0, 0xF0, 0x18, 0x01, 0x6E, 0x00, 0x0F, 0x00, 0x03, 0x00, 0x00, 0x00,
0x16, 0x01, 0x0F, 0x00, 0x01, 0x00, 0x01, 0x00, 0x17, 0x01, 0x0F, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1B, 0x01, 0x0F, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x12, 0x01, 0x3F, 0x80, 0x0F, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x45, 0x00,
0x41, 0x00, 0x3F, 0x80, 0x10, 0x11, 0x11, 0x38, 0x00, 0x90, 0x46, 0x00,
0x14, 0xAE, 0x47, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x68, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x00, 0x2F, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0xC0, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x80, 0xBF, 0xC1, 0x02, 0xFF, 0x00,
0x00, 0x00, 0x00, 0x00, 0x88, 0x88, 0x08, 0x3C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0A, 0xD7, 0xA3, 0xBB, 0x00, 0x00, 0x80, 0xBF, 0x00, 0x00, 0x80, 0x3F,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x5E, 0x02, 0x02, 0x00,
0x01, 0x00, 0x00, 0x00, 0x5F, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x80,
0x27, 0x02, 0x0F, 0x00, 0x01, 0x00, 0x00, 0x00, 0x53, 0x02, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x45, 0x02, 0x01, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x32, 0x02, 0x0F, 0x00, 0x3E, 0x00, 0x00, 0x3F, 0x33, 0x02, 0x2F, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x02, 0x2F, 0x80, 0x10, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x00, 0x3F, 0x33, 0x02, 0x2F, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7C, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x02, 0x2F, 0x80,
0x10, 0x3E, 0x00, 0x00, 0x00, 0x68, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x3F,
0x33, 0x02, 0x2F, 0x80, 0xE0, 0x46, 0x00, 0x00, 0x00, 0x40, 0x43, 0x00,
0x00, 0x00, 0x00, 0x00, 0x33, 0x02, 0x2F, 0x80, 0x00, 0x3F, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x3F, 0x33, 0x02, 0x2F, 0x80,
0xE0, 0x46, 0x00, 0x00, 0x00, 0x7C, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x02, 0x2F, 0x80, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x68, 0x3E, 0x00,
0x01, 0x00, 0x00, 0x00, 0x45, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x53, 0x02, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x31, 0x02, 0x0F, 0x00,
0x01, 0x00, 0x00, 0x00, 0x11, 0x01, 0x0F, 0x00, 0x01, 0x00, 0x00, 0x00,
0x10, 0x01, 0x0F, 0x00, 0x01, 0x00, 0x00, 0x00, 0x63, 0x00, 0x0F, 0x00,
0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x0F, 0x00, 0x78, 0x56, 0x34, 0x12,
0x10, 0x00, 0x0F, 0x00
};
// 240x160 with bilinear scaling, no filter.
/*alignas(16) static const u8 gbaGpuList2[448] =
{
0x01, 0x00, 0x00, 0x00, 0x10, 0x01, 0x0F, 0x00, 0x00, 0x00, 0x06, 0x03,
0x1C, 0x01, 0x2F, 0x80, 0x00, 0x00, 0x03, 0x03, 0xF0, 0xF0, 0x18, 0x01,
0xF0, 0xF0, 0x18, 0x01, 0x6E, 0x00, 0x0F, 0x00, 0x03, 0x00, 0x00, 0x00,
0x16, 0x01, 0x0F, 0x00, 0x01, 0x00, 0x01, 0x00, 0x17, 0x01, 0x0F, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1B, 0x01, 0x0F, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x12, 0x01, 0x3F, 0x80, 0x0F, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x45, 0x00,
0x41, 0x00, 0x3F, 0x80, 0x10, 0x11, 0x11, 0x38, 0x00, 0x90, 0x46, 0x00,
0x14, 0xAE, 0x47, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x68, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x00, 0x2F, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0xC0, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x80, 0xBF, 0xC1, 0x02, 0xFF, 0x00,
0x00, 0x00, 0x00, 0x00, 0x88, 0x88, 0x08, 0x3C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0A, 0xD7, 0xA3, 0xBB, 0x00, 0x00, 0x80, 0xBF, 0x00, 0x00, 0x80, 0x3F,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x5E, 0x02, 0x02, 0x00,
0x01, 0x00, 0x00, 0x00, 0x5F, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x80,
0x27, 0x02, 0x0F, 0x00, 0x01, 0x00, 0x00, 0x00, 0x53, 0x02, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x45, 0x02, 0x01, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x32, 0x02, 0x0F, 0x00, 0x3E, 0x00, 0x00, 0x3F, 0x33, 0x02, 0x2F, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x02, 0x2F, 0x80, 0x80, 0x3D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x00, 0x3F, 0x33, 0x02, 0x2F, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7C, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x02, 0x2F, 0x80,
0x80, 0x3D, 0x00, 0x00, 0x00, 0xE0, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x3F,
0x33, 0x02, 0x2F, 0x80, 0xE0, 0x46, 0x00, 0x00, 0x00, 0x40, 0x43, 0x00,
0x00, 0x00, 0x00, 0x00, 0x33, 0x02, 0x2F, 0x80, 0x00, 0x3F, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x3F, 0x33, 0x02, 0x2F, 0x80,
0xE0, 0x46, 0x00, 0x00, 0x00, 0x7C, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x02, 0x2F, 0x80, 0x00, 0x3F, 0x00, 0x00, 0x00, 0xE0, 0x3E, 0x00,
0x01, 0x00, 0x00, 0x00, 0x45, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x53, 0x02, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x31, 0x02, 0x0F, 0x00,
0x01, 0x00, 0x00, 0x00, 0x11, 0x01, 0x0F, 0x00, 0x01, 0x00, 0x00, 0x00,
0x10, 0x01, 0x0F, 0x00, 0x01, 0x00, 0x00, 0x00, 0x63, 0x00, 0x0F, 0x00,
0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x0F, 0x00, 0x78, 0x56, 0x34, 0x12,
0x10, 0x00, 0x0F, 0x00
};*/

View File

@ -0,0 +1,80 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2018 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "mem_map.h"
#define CFG11_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x40000)
#define REG_CFG11_FIQ_MASK *(( vu8*)(CFG11_REGS_BASE + 0x104))
#define REG_CFG11_UNK105 *(( vu8*)(CFG11_REGS_BASE + 0x105)) // Debug related? Mask?
#define REG_CFG11_UNK108 *(( vu8*)(CFG11_REGS_BASE + 0x108)) // LGY gamecard related?
#define REG_CFG11_CDMA_CNT *(( vu8*)(CFG11_REGS_BASE + 0x10C))
#define REG_CFG11_UNK110 *(( vu8*)(CFG11_REGS_BASE + 0x110)) // VRAM related?
#define REG_CFG11_GPUPROT *(( vu16*)(CFG11_REGS_BASE + 0x140))
#define REG_CFG11_WIFI_POWER *(( vu8*)(CFG11_REGS_BASE + 0x180)) // Used for flight mode?
#define REG_CFG11_SPI_CNT *(( vu16*)(CFG11_REGS_BASE + 0x1C0))
#define REG_CFG11_UNK200 *(( vu32*)(CFG11_REGS_BASE + 0x200)) // GPIO3 related? 8x4 bits.
#define REG_CFG11_GPU_N3DS_CNT *(( vu8*)(CFG11_REGS_BASE + 0x400)) // New3DS-only.
#define REG_CFG11_CDMA_PERIPHERALS *(( vu32*)(CFG11_REGS_BASE + 0x410)) // New3DS-only.
#define REG_CFG11_BOOTROM_OVERLAY_CNT *(( vu8*)(CFG11_REGS_BASE + 0x420)) // New3DS-only.
#define REG_CFG11_BOOTROM_OVERLAY_VAL *(( vu32*)(CFG11_REGS_BASE + 0x424)) // New3DS-only.
#define REG_CFG11_UNK428 *(( vu8*)(CFG11_REGS_BASE + 0x428)) // New3DS-only. 1 bit. Enable CPU core 1 access to overlay regs?
#define REG_CFG11_SOCINFO *((const vu16*)(CFG11_REGS_BASE + 0xFFC))
// REG_CFG11_FIQ_MASK
#define FIQ_MASK_CPU0 (1u)
#define FIQ_MASK_CPU1 (1u<<1)
#define FIQ_MASK_CPU2 (1u<<2) // New3DS-only.
#define FIQ_MASK_CPU3 (1u<<3) // New3DS-only.
// REG_CFG11_CDMA_CNT
#define CDMA_CNT_MIC_E (1u)
#define CDMA_CNT_NTRCARD_E (1u<<1)
#define CDMA_CNT_CAM1_E (1u<<2)
#define CDMA_CNT_CAM2_E (1u<<3)
#define CDMA_CNT_SDIO2_E (1u<<4) // WiFi
#define CDMA_CNT_SDIO3_E (1u<<5)
// REG_CFG11_GPUPROT
// TODO
// REG_CFG11_WIFI_POWER
#define WIFI_POWER_ON (1u)
// REG_CFG11_SPI_CNT
#define SPI_CNT_SPI1_NEW_IF (1u) // New interface (NSPI).
#define SPI_CNT_SPI2_NEW_IF (1u<<1)
#define SPI_CNT_SPI3_NEW_IF (1u<<2)
// REG_CFG11_GPU_N3DS_CNT
#define GPU_N3DS_CNT_N3DS_MODE (1u) // Enable access to mem extensions.
#define GPU_N3DS_CNT_TEX_FIX (1u<<1) // Fixes some texture glitches in New3DS mode.
// REG_CFG11_CDMA_PERIPHERALS
#define CDMA_PERIPHERALS_ALL (0x3FFFFu)
// REG_CFG11_BOOTROM_OVERLAY_CNT
#define BOOTROM_OVERLAY_CNT_E (1u)
// REG_CFG11_SOCINFO
#define SOCINFO_O3DS (1u) // Also set on New3DS.
#define SOCINFO_N3DS_PROTO (1u<<1) // Never saw the daylight?
#define SOCINFO_N3DS (1u<<2) // Set on New3DS.

View File

@ -0,0 +1,56 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2019 Sergi Granell (xerpi), Paul LaMendola (paulguy), derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
typedef struct
{
u16 touchX[5];
u16 touchY[5];
u16 cpadY[8];
u16 cpadX[8];
} CdcAdcData;
/**
* @brief Initialize CODEC for Circle-Pad/Touchscreen/Sound.
*/
void CODEC_init(void);
/**
* @brief Deinitializes the CODEC chip for sleep or poweroff.
*/
void CODEC_deinit(void);
/**
* @brief The opposite of CODEC_deinit(). Does a partial init.
*/
void CODEC_wakeup(void);
/**
* @brief Get raw ADC data for Circle-Pad/Touchscreen.
*
* @param data The output data pointer. Must be 4 bytes aligned.
*
* @return Returns true if data was available and false otherwise.
*/
bool CODEC_getRawAdcData(CdcAdcData *data);

View File

@ -0,0 +1,186 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2019 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#include "mem_map.h"
#define CSND_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x3000)
#define REG_CSND_MASTER_VOL *((vu16*)(CSND_REGS_BASE + 0x000)) // CSND master volume 0-0x8000
#define REG_CSND_UNK_CNT *((vu16*)(CSND_REGS_BASE + 0x002))
// 32 sound channels. PSG on channel 8-13 and noise 14-15.
#define REG_CSND_CH_CNT(n) *((vu16*)(CSND_REGS_BASE + 0x400 + ((n) * 32)))
#define REG_CSND_CH_SR(n) *((vs16*)(CSND_REGS_BASE + 0x402 + ((n) * 32))) // Samplerate
#define REG_CSND_CH_VOL_R(n) *((vu16*)(CSND_REGS_BASE + 0x404 + ((n) * 32))) // 0-0x8000
#define REG_CSND_CH_VOL_L(n) *((vu16*)(CSND_REGS_BASE + 0x406 + ((n) * 32))) // 0-0x8000
#define REG_CSND_CH_VOL(n) *((vu32*)(CSND_REGS_BASE + 0x404 + ((n) * 32))) // R and L combined
#define REG_CSND_CH_CAPVOL_R(n) *((vu16*)(CSND_REGS_BASE + 0x408 + ((n) * 32))) // Unconfirmed. 0-0x8000
#define REG_CSND_CH_CAPVOL_L(n) *((vu16*)(CSND_REGS_BASE + 0x40A + ((n) * 32))) // Unconfirmed. 0-0x8000
#define REG_CSND_CH_CAPVOL(n) *((vu32*)(CSND_REGS_BASE + 0x408 + ((n) * 32))) // R and L combined
#define REG_CSND_CH_ST_ADDR(n) *((vu32*)(CSND_REGS_BASE + 0x40C + ((n) * 32))) // Start address and playback position
#define REG_CSND_CH_SIZE(n) *((vu32*)(CSND_REGS_BASE + 0x410 + ((n) * 32))) // Size in bytes
#define REG_CSND_CH_LP_ADDR(n) *((vu32*)(CSND_REGS_BASE + 0x414 + ((n) * 32))) // Loop restart address
#define REG_CSND_CH_ST_ADPCM(n) *((vu32*)(CSND_REGS_BASE + 0x418 + ((n) * 32))) // Start IMA-ADPCM state
#define REG_CSND_CH_LP_ADPCM(n) *((vu32*)(CSND_REGS_BASE + 0x41C + ((n) * 32))) // Loop Restart IMA-ADPCM state
// 2 capture units for right and left side.
#define REG_CSND_CAP_CNT(n) *((vu16*)(CSND_REGS_BASE + 0x800 + ((n) * 16)))
#define REG_CSND_CAP_SR(n) *((vs16*)(CSND_REGS_BASE + 0x804 + ((n) * 16))) // Samplerate
#define REG_CSND_CAP_SIZE(n) *((vu32*)(CSND_REGS_BASE + 0x808 + ((n) * 16))) // Capture length in bytes
#define REG_CSND_CAP_ADDR(n) *((vu32*)(CSND_REGS_BASE + 0x80C + ((n) * 16))) // Address
// REG_CSND_CH_CNT
#define CSND_CH_DUTY(d) (d) // For PSG (channel 8-13) only. In 12.5% units. 0 = high/12.5%.
#define CSND_CH_LINEAR_INTERP (1u<<6) // Linear interpolation
#define CSND_CH_HOLD (1u<<7) // Hold last sample after one shot.
#define CSND_CH_PLAYING (1u<<14)
#define CSND_CH_START (1u<<15)
enum
{
CSND_CH_RPT_MANUAL = 0u<<10,
CSND_CH_RPT_LOOP = 1u<<10,
CSND_CH_RPT_ONE_SHOT = 2u<<10
};
enum
{
CSND_CH_FMT_PCM8 = 0u<<12, // Signed PCM8
CSND_CH_FMT_PCM16 = 1u<<12, // Signed PCM16 little endian
CSND_CH_FMT_IMA_ADPCM = 2u<<12,
CSND_CH_FMT_PSG_NOISE = 3u<<12
};
// REG_CSND_CAP_CNT
#define CSND_CAP_RPT_LOOP (0u)
#define CSND_CAP_RPT_ONE_SHOT (1u)
#define CSND_CAP_FMT_PCM16 (0u) // Signed PCM16 little endian
#define CSND_CAP_FMT_PCM8 (1u<<1) // Signed PCM8
#define CSND_CAP_UNK2 (1u<<2)
#define CSND_CAP_START (1u<<15)
// Samplerate helpers
#define CSND_SAMPLERATE(s) (-(s16)(67027964u / (s)))
#define CSND_PSG_FREQ(f) (CSND_SAMPLERATE(32u * (f)))
/**
* @brief Initializes the CSND hardware.
*/
void CSND_init(void);
/**
* @brief Calculates the left and right volumes.
*
* @param[in] lvol The left volume.
* @param[in] rvol The right volume.
*
* @return The volume pair needed for CSND_setupCh().
*/
static inline u32 CSND_calcVol(float lvol, float rvol)
{
return (u32)(lvol * 32768.0f)<<16 | (u16)(rvol * 32768.0f);
}
/**
* @brief Sets up a channel for sound playback (in paused state).
*
* @param[in] ch The sound channel. 0-31.
* @param[in] sampleRate The sample rate.
* @param[in] vol The L/R volume pair.
* @param[in] data The start address.
* @param[in] data2 The loop restart address.
* @param[in] size The size.
* @param[in] flags The flags.
*/
void CSND_setupCh(u8 ch, s16 sampleRate, u32 vol, const u32 *const data, const u32 *const data2, u32 size, u16 flags);
/**
* @brief Pauses or unpauses a sound channel.
*
* @param[in] ch The sound channel. 0-31.
* @param[in] playing The play state.
*/
static inline void CSND_setChState(u8 ch, bool playing)
{
REG_CSND_CH_CNT(ch) = (REG_CSND_CH_CNT(ch) & ~CSND_CH_PLAYING) | ((u16)playing<<14);
}
/**
* @brief Returns the current audio buffer position (address).
*
* @param[in] ch The sound channel. 0-31.
*
* @return The playback position (address).
*/
static inline u32 CSND_getChPos(u8 ch)
{
return REG_CSND_CH_ST_ADDR(ch);
}
/**
* @brief Stops a sound channel.
*
* @param[in] ch The sound channel. 0-31.
*/
static inline void CSND_stopCh(u8 ch)
{
REG_CSND_CH_CNT(ch) = 0; // Stop
}
/**
* @brief Captures the output of all left/right sound channels combined.
*
* @param[in] ch The capture side. 0 = right, 1 = left.
* @param[in] sampleRate The sample rate.
* @param data The output address.
* @param[in] size The size.
* @param[in] flags The flags.
*/
void CSND_startCap(u8 ch, s16 sampleRate, u32 *const data, u32 size, u16 flags);
/**
* @brief Returns the current capture buffer position (address).
*
* @param[in] ch The capture side. 0 = right, 1 = left.
*
* @return The capture position (address).
*/
static inline u32 CSND_getCapPos(u8 ch)
{
return REG_CSND_CAP_ADDR(ch);
}
/**
* @brief Stops a capture channel.
*
* @param[in] ch The capture side. 0 = right, 1 = left.
*/
static inline void CSND_stopCap(u8 ch)
{
REG_CSND_CAP_CNT(ch) = 0;
}

View File

@ -0,0 +1,95 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#define GPIO_INPUT (0u)
#define GPIO_OUTPUT (1u)
#define GPIO_EDGE_FALLING (0u)
#define GPIO_EDGE_RISING (1u<<1)
#define GPIO_IRQ_ENABLE (1u<<2)
// bits 3-7 pin number, bits 0-3 reg index.
#define MAKE_GPIO(pin, reg) ((pin)<<3 | (reg))
typedef enum
{
GPIO_1_0 = MAKE_GPIO(0u, 0u),
GPIO_1_1 = MAKE_GPIO(1u, 0u),
GPIO_1_2 = MAKE_GPIO(2u, 0u),
GPIO_2_0 = MAKE_GPIO(0u, 1u),
GPIO_2_1 = MAKE_GPIO(1u, 1u),
GPIO_2_2 = MAKE_GPIO(0u, 2u), // REG_GPIO2_DAT2
GPIO_3_0 = MAKE_GPIO(0u, 3u),
GPIO_3_1 = MAKE_GPIO(1u, 3u),
GPIO_3_2 = MAKE_GPIO(2u, 3u),
GPIO_3_3 = MAKE_GPIO(3u, 3u),
GPIO_3_4 = MAKE_GPIO(4u, 3u),
GPIO_3_5 = MAKE_GPIO(5u, 3u),
GPIO_3_6 = MAKE_GPIO(6u, 3u),
GPIO_3_7 = MAKE_GPIO(7u, 3u),
GPIO_3_8 = MAKE_GPIO(8u, 3u),
GPIO_3_9 = MAKE_GPIO(9u, 3u),
GPIO_3_10 = MAKE_GPIO(10u, 3u),
GPIO_3_11 = MAKE_GPIO(11u, 3u),
GPIO_3_12 = MAKE_GPIO(0u, 4u), // REG_GPIO3_DAT2
// Aliases
GPIO_1_TOUCHSCREEN = GPIO_1_1, // Unset while touchscreen pen down. Unused after CODEC init.
GPIO_1_SHELL = GPIO_1_2, // 1 when closed.
GPIO_2_HEADPH_JACK = GPIO_2_0, // Used after CODEC init.
GPIO_3_HEADPH_JACK = GPIO_3_8, // Unused/other function after CODEC init.
GPIO_3_MCU = GPIO_3_9
} Gpio;
#undef MAKE_GPIO
/**
* @brief Configures the specified GPIO.
*
* @param[in] gpio The gpio.
* @param[in] cfg The configuration.
*/
void GPIO_config(Gpio gpio, u8 cfg);
/**
* @brief Reads a GPIO pin.
*
* @param[in] gpio The gpio.
*
* @return The state. Either 0 or 1.
*/
bool GPIO_read(Gpio gpio);
/**
* @brief Writes a GPIO pin.
*
* @param[in] gpio The gpio.
* @param[in] val The value. Must be 0 or 1.
*/
void GPIO_write(Gpio gpio, bool val);

View File

@ -0,0 +1,769 @@
// From https://github.com/smealum/ctrulib/blob/master/libctru/include/3ds/gpu/registers.h
/**
* @file registers.h
* @description GPU registers.
*/
#pragma once
///@name Miscellaneous registers (0x000-0x03F)
///@{
#define GPUREG_IRQ_ACK 0x0000 ///< Acknowledge P3D IRQ.
#define GPUREG_0001 0x0001 ///< Unknown.
#define GPUREG_0002 0x0002 ///< Unknown.
#define GPUREG_0003 0x0003 ///< Unknown.
#define GPUREG_0004 0x0004 ///< Unknown.
#define GPUREG_0005 0x0005 ///< Unknown.
#define GPUREG_0006 0x0006 ///< Unknown.
#define GPUREG_0007 0x0007 ///< Unknown.
#define GPUREG_0008 0x0008 ///< Unknown.
#define GPUREG_0009 0x0009 ///< Unknown.
#define GPUREG_000A 0x000A ///< Unknown.
#define GPUREG_000B 0x000B ///< Unknown.
#define GPUREG_000C 0x000C ///< Unknown.
#define GPUREG_000D 0x000D ///< Unknown.
#define GPUREG_000E 0x000E ///< Unknown.
#define GPUREG_000F 0x000F ///< Unknown.
#define GPUREG_FINALIZE 0x0010 ///< Used to finalize GPU drawing.
#define GPUREG_0011 0x0011 ///< Unknown.
#define GPUREG_0012 0x0012 ///< Unknown.
#define GPUREG_0013 0x0013 ///< Unknown.
#define GPUREG_0014 0x0014 ///< Unknown.
#define GPUREG_0015 0x0015 ///< Unknown.
#define GPUREG_0016 0x0016 ///< Unknown.
#define GPUREG_0017 0x0017 ///< Unknown.
#define GPUREG_0018 0x0018 ///< Unknown.
#define GPUREG_0019 0x0019 ///< Unknown.
#define GPUREG_001A 0x001A ///< Unknown.
#define GPUREG_001B 0x001B ///< Unknown.
#define GPUREG_001C 0x001C ///< Unknown.
#define GPUREG_001D 0x001D ///< Unknown.
#define GPUREG_001E 0x001E ///< Unknown.
#define GPUREG_001F 0x001F ///< Unknown.
#define GPUREG_IRQ_CMP 0x0020 ///< Triggers a P3D IRQ when the value written to GPUREG_FINALIZE matches this.
#define GPUREG_0021 0x0021 ///< Unknown.
#define GPUREG_0022 0x0022 ///< Unknown.
#define GPUREG_0023 0x0023 ///< Unknown.
#define GPUREG_0024 0x0024 ///< Unknown.
#define GPUREG_0025 0x0025 ///< Unknown.
#define GPUREG_0026 0x0026 ///< Unknown.
#define GPUREG_0027 0x0027 ///< Unknown.
#define GPUREG_0028 0x0028 ///< Unknown.
#define GPUREG_0029 0x0029 ///< Unknown.
#define GPUREG_002A 0x002A ///< Unknown.
#define GPUREG_002B 0x002B ///< Unknown.
#define GPUREG_002C 0x002C ///< Unknown.
#define GPUREG_002D 0x002D ///< Unknown.
#define GPUREG_002E 0x002E ///< Unknown.
#define GPUREG_002F 0x002F ///< Unknown.
#define GPUREG_IRQ_MASK 0x0030 ///< IRQ mask. Each bit 0 = enable.
#define GPUREG_0031 0x0031 ///< Unknown.
#define GPUREG_0032 0x0032 ///< Unknown.
#define GPUREG_0033 0x0033 ///< Unknown.
#define GPUREG_IRQ_AUTOSTOP 0x0034 ///< 1 = stop cmd list processing on IRQ.
#define GPUREG_0035 0x0035 ///< Unknown.
#define GPUREG_0036 0x0036 ///< Unknown.
#define GPUREG_0037 0x0037 ///< Unknown.
#define GPUREG_0038 0x0038 ///< Unknown.
#define GPUREG_0039 0x0039 ///< Unknown.
#define GPUREG_003A 0x003A ///< Unknown.
#define GPUREG_003B 0x003B ///< Unknown.
#define GPUREG_003C 0x003C ///< Unknown.
#define GPUREG_003D 0x003D ///< Unknown.
#define GPUREG_003E 0x003E ///< Unknown.
#define GPUREG_003F 0x003F ///< Unknown.
///@}
///@name Rasterizer registers (0x040-0x07F)
///@{
#define GPUREG_FACECULLING_CONFIG 0x0040 ///< Face culling configuration.
#define GPUREG_VIEWPORT_WIDTH 0x0041 ///< Viewport width.
#define GPUREG_VIEWPORT_INVW 0x0042 ///< Inverted viewport width.
#define GPUREG_VIEWPORT_HEIGHT 0x0043 ///< Viewport height.
#define GPUREG_VIEWPORT_INVH 0x0044 ///< Inverted viewport height.
#define GPUREG_0045 0x0045 ///< Unknown
#define GPUREG_0046 0x0046 ///< Unknown
#define GPUREG_FRAGOP_CLIP 0x0047 ///< Unknown
#define GPUREG_FRAGOP_CLIP_DATA0 0x0048 ///< Unknown
#define GPUREG_FRAGOP_CLIP_DATA1 0x0049 ///< Unknown
#define GPUREG_FRAGOP_CLIP_DATA2 0x004A ///< Unknown
#define GPUREG_FRAGOP_CLIP_DATA3 0x004B ///< Unknown
#define GPUREG_004C 0x004C ///< Unknown
#define GPUREG_DEPTHMAP_SCALE 0x004D ///< Depth map scale.
#define GPUREG_DEPTHMAP_OFFSET 0x004E ///< Depth map offset.
#define GPUREG_SH_OUTMAP_TOTAL 0x004F ///< Shader output map total.
#define GPUREG_SH_OUTMAP_O0 0x0050 ///< Shader output map 0.
#define GPUREG_SH_OUTMAP_O1 0x0051 ///< Shader output map 1.
#define GPUREG_SH_OUTMAP_O2 0x0052 ///< Shader output map 2.
#define GPUREG_SH_OUTMAP_O3 0x0053 ///< Shader output map 3.
#define GPUREG_SH_OUTMAP_O4 0x0054 ///< Shader output map 4.
#define GPUREG_SH_OUTMAP_O5 0x0055 ///< Shader output map 5.
#define GPUREG_SH_OUTMAP_O6 0x0056 ///< Shader output map 6.
#define GPUREG_0057 0x0057 ///< Unknown
#define GPUREG_0058 0x0058 ///< Unknown
#define GPUREG_0059 0x0059 ///< Unknown
#define GPUREG_005A 0x005A ///< Unknown
#define GPUREG_005B 0x005B ///< Unknown
#define GPUREG_005C 0x005C ///< Unknown
#define GPUREG_005D 0x005D ///< Unknown
#define GPUREG_005E 0x005E ///< Unknown
#define GPUREG_005F 0x005F ///< Unknown
#define GPUREG_0060 0x0060 ///< Unknown
#define GPUREG_EARLYDEPTH_FUNC 0x0061 ///< Unknown
#define GPUREG_EARLYDEPTH_TEST1 0x0062 ///< Unknown
#define GPUREG_EARLYDEPTH_CLEAR 0x0063 ///< Unknown
#define GPUREG_SH_OUTATTR_MODE 0x0064 ///< Shader output attributes mode.
#define GPUREG_SCISSORTEST_MODE 0x0065 ///< Scissor test mode.
#define GPUREG_SCISSORTEST_POS 0x0066 ///< Scissor test position.
#define GPUREG_SCISSORTEST_DIM 0x0067 ///< Scissor text dimensions.
#define GPUREG_VIEWPORT_XY 0x0068 ///< Viewport X and Y.
#define GPUREG_0069 0x0069 ///< Unknown
#define GPUREG_EARLYDEPTH_DATA 0x006A ///< Unknown
#define GPUREG_006B 0x006B ///< Unknown
#define GPUREG_006C 0x006C ///< Unknown
#define GPUREG_DEPTHMAP_ENABLE 0x006D ///< Depth map enable.
#define GPUREG_RENDERBUF_DIM 0x006E ///< Renderbuffer dimensions.
#define GPUREG_SH_OUTATTR_CLOCK 0x006F ///< Shader output attributes clock enable.
#define GPUREG_0070 0x0070 ///< Unknown
#define GPUREG_0071 0x0071 ///< Unknown
#define GPUREG_0072 0x0072 ///< Unknown
#define GPUREG_0073 0x0073 ///< Unknown
#define GPUREG_0074 0x0074 ///< Unknown
#define GPUREG_0075 0x0075 ///< Unknown
#define GPUREG_0076 0x0076 ///< Unknown
#define GPUREG_0077 0x0077 ///< Unknown
#define GPUREG_0078 0x0078 ///< Unknown
#define GPUREG_0079 0x0079 ///< Unknown
#define GPUREG_007A 0x007A ///< Unknown
#define GPUREG_007B 0x007B ///< Unknown
#define GPUREG_007C 0x007C ///< Unknown
#define GPUREG_007D 0x007D ///< Unknown
#define GPUREG_007E 0x007E ///< Unknown
#define GPUREG_007F 0x007F ///< Unknown
///@}
///@name Texturing registers (0x080-0x0FF)
///@{
#define GPUREG_TEXUNIT_CONFIG 0x0080 ///< Texture unit configuration.
#define GPUREG_TEXUNIT0_BORDER_COLOR 0x0081 ///< Texture unit 0 border color.
#define GPUREG_TEXUNIT0_DIM 0x0082 ///< Texture unit 0 dimensions.
#define GPUREG_TEXUNIT0_PARAM 0x0083 ///< Texture unit 0 parameters.
#define GPUREG_TEXUNIT0_LOD 0x0084 ///< Texture unit 0 LOD.
#define GPUREG_TEXUNIT0_ADDR1 0x0085 ///< Texture unit 0 address.
#define GPUREG_TEXUNIT0_ADDR2 0x0086 ///< Unknown.
#define GPUREG_TEXUNIT0_ADDR3 0x0087 ///< Unknown.
#define GPUREG_TEXUNIT0_ADDR4 0x0088 ///< Unknown.
#define GPUREG_TEXUNIT0_ADDR5 0x0089 ///< Unknown.
#define GPUREG_TEXUNIT0_ADDR6 0x008A ///< Unknown.
#define GPUREG_TEXUNIT0_SHADOW 0x008B ///< Unknown.
#define GPUREG_008C 0x008C ///< Unknown.
#define GPUREG_008D 0x008D ///< Unknown.
#define GPUREG_TEXUNIT0_TYPE 0x008E ///< Texture unit 0 type.
#define GPUREG_LIGHTING_ENABLE0 0x008F ///< Lighting toggle.
#define GPUREG_0090 0x0090 ///< Unknown.
#define GPUREG_TEXUNIT1_BORDER_COLOR 0x0091 ///< Texture unit 1 border color.
#define GPUREG_TEXUNIT1_DIM 0x0092 ///< Texture unit 1 dimensions.
#define GPUREG_TEXUNIT1_PARAM 0x0093 ///< Texture unit 1 parameters.
#define GPUREG_TEXUNIT1_LOD 0x0094 ///< Texture unit 1 LOD.
#define GPUREG_TEXUNIT1_ADDR 0x0095 ///< Texture unit 1 address.
#define GPUREG_TEXUNIT1_TYPE 0x0096 ///< Texture unit 1 type.
#define GPUREG_0097 0x0097 ///< Unknown.
#define GPUREG_0098 0x0098 ///< Unknown.
#define GPUREG_TEXUNIT2_BORDER_COLOR 0x0099 ///< Texture unit 2 border color.
#define GPUREG_TEXUNIT2_DIM 0x009A ///< Texture unit 2 dimensions.
#define GPUREG_TEXUNIT2_PARAM 0x009B ///< Texture unit 2 parameters.
#define GPUREG_TEXUNIT2_LOD 0x009C ///< Texture unit 2 LOD.
#define GPUREG_TEXUNIT2_ADDR 0x009D ///< Texture unit 2 address.
#define GPUREG_TEXUNIT2_TYPE 0x009E ///< Texture unit 2 type.
#define GPUREG_009F 0x009F ///< Unknown.
#define GPUREG_00A0 0x00A0 ///< Unknown.
#define GPUREG_00A1 0x00A1 ///< Unknown.
#define GPUREG_00A2 0x00A2 ///< Unknown.
#define GPUREG_00A3 0x00A3 ///< Unknown.
#define GPUREG_00A4 0x00A4 ///< Unknown.
#define GPUREG_00A5 0x00A5 ///< Unknown.
#define GPUREG_00A6 0x00A6 ///< Unknown.
#define GPUREG_00A7 0x00A7 ///< Unknown.
#define GPUREG_TEXUNIT3_PROCTEX0 0x00A8 ///< Unknown.
#define GPUREG_TEXUNIT3_PROCTEX1 0x00A9 ///< Unknown.
#define GPUREG_TEXUNIT3_PROCTEX2 0x00AA ///< Unknown.
#define GPUREG_TEXUNIT3_PROCTEX3 0x00AB ///< Unknown.
#define GPUREG_TEXUNIT3_PROCTEX4 0x00A ///< Unknown.
#define GPUREG_TEXUNIT3_PROCTEX5 0x00D ///< Unknown.
#define GPUREG_00AE 0x00AE ///< Unknown.
#define GPUREG_PROCTEX_LUT 0x00AF ///< Unknown.
#define GPUREG_PROCTEX_LUT_DATA0 0x00B0 ///< Unknown.
#define GPUREG_PROCTEX_LUT_DATA1 0x00B1 ///< Unknown.
#define GPUREG_PROCTEX_LUT_DATA2 0x00B2 ///< Unknown.
#define GPUREG_PROCTEX_LUT_DATA3 0x00B3 ///< Unknown.
#define GPUREG_PROCTEX_LUT_DATA4 0x00B4 ///< Unknown.
#define GPUREG_PROCTEX_LUT_DATA5 0x00B5 ///< Unknown.
#define GPUREG_PROCTEX_LUT_DATA6 0x00B6 ///< Unknown.
#define GPUREG_PROCTEX_LUT_DATA7 0x00B7 ///< Unknown.
#define GPUREG_00B8 0x00B8 ///< Unknown.
#define GPUREG_00B9 0x00B9 ///< Unknown.
#define GPUREG_00BA 0x00BA ///< Unknown.
#define GPUREG_00BB 0x00BB ///< Unknown.
#define GPUREG_00BC 0x00BC ///< Unknown.
#define GPUREG_00BD 0x00BD ///< Unknown.
#define GPUREG_00BE 0x00BE ///< Unknown.
#define GPUREG_00BF 0x00BF ///< Unknown.
#define GPUREG_TEXENV0_SOURCE 0x00C0 ///< Texture env 0 source.
#define GPUREG_TEXENV0_OPERAND 0x00C1 ///< Texture env 0 operand.
#define GPUREG_TEXENV0_COMBINER 0x00C2 ///< Texture env 0 combiner.
#define GPUREG_TEXENV0_COLOR 0x00C3 ///< Texture env 0 color.
#define GPUREG_TEXENV0_SCALE 0x00C4 ///< Texture env 0 scale.
#define GPUREG_00C5 0x00C5 ///< Unknown.
#define GPUREG_00C6 0x00C6 ///< Unknown.
#define GPUREG_00C7 0x00C7 ///< Unknown.
#define GPUREG_TEXENV1_SOURCE 0x00C8 ///< Texture env 1 source.
#define GPUREG_TEXENV1_OPERAND 0x00C9 ///< Texture env 1 operand.
#define GPUREG_TEXENV1_COMBINER 0x00CA ///< Texture env 1 combiner.
#define GPUREG_TEXENV1_COLOR 0x00CB ///< Texture env 1 color.
#define GPUREG_TEXENV1_SCALE 0x00CC ///< Texture env 1 scale.
#define GPUREG_00CD 0x00CD ///< Unknown.
#define GPUREG_00CE 0x00CE ///< Unknown.
#define GPUREG_00CF 0x00CF ///< Unknown.
#define GPUREG_TEXENV2_SOURCE 0x00D0 ///< Texture env 2 source.
#define GPUREG_TEXENV2_OPERAND 0x00D1 ///< Texture env 2 operand.
#define GPUREG_TEXENV2_COMBINER 0x00D2 ///< Texture env 2 combiner.
#define GPUREG_TEXENV2_COLOR 0x00D3 ///< Texture env 2 color.
#define GPUREG_TEXENV2_SCALE 0x00D4 ///< Texture env 2 scale.
#define GPUREG_00D5 0x00D5 ///< Unknown.
#define GPUREG_00D6 0x00D6 ///< Unknown.
#define GPUREG_00D7 0x00D7 ///< Unknown.
#define GPUREG_TEXENV3_SOURCE 0x00D8 ///< Texture env 3 source.
#define GPUREG_TEXENV3_OPERAND 0x00D9 ///< Texture env 3 operand.
#define GPUREG_TEXENV3_COMBINER 0x00DA ///< Texture env 3 combiner.
#define GPUREG_TEXENV3_COLOR 0x00DB ///< Texture env 3 color.
#define GPUREG_TEXENV3_SCALE 0x00DC ///< Texture env 3 scale.
#define GPUREG_00DD 0x00DD ///< Unknown.
#define GPUREG_00DE 0x00DE ///< Unknown.
#define GPUREG_00DF 0x00DF ///< Unknown.
#define GPUREG_TEXENV_UPDATE_BUFFER 0x00E0 ///< Texture env buffer update flag.
#define GPUREG_FOG_COLOR 0x00E1 ///< Unknown.
#define GPUREG_00E2 0x00E2 ///< Unknown.
#define GPUREG_00E3 0x00E3 ///< Unknown.
#define GPUREG_GAS_ATTENUATION 0x00E4 ///< Unknown.
#define GPUREG_GAS_ACCMAX 0x00E5 ///< Unknown.
#define GPUREG_FOG_LUT_INDEX 0x00E6 ///< Unknown.
#define GPUREG_00E7 0x00E7 ///< Unknown.
#define GPUREG_FOG_LUT_DATA0 0x00E8 ///< Unknown.
#define GPUREG_FOG_LUT_DATA1 0x00E9 ///< Unknown.
#define GPUREG_FOG_LUT_DATA2 0x00EA ///< Unknown.
#define GPUREG_FOG_LUT_DATA3 0x00EB ///< Unknown.
#define GPUREG_FOG_LUT_DATA4 0x00EC ///< Unknown.
#define GPUREG_FOG_LUT_DATA5 0x00ED ///< Unknown.
#define GPUREG_FOG_LUT_DATA6 0x00EE ///< Unknown.
#define GPUREG_FOG_LUT_DATA7 0x00EF ///< Unknown.
#define GPUREG_TEXENV4_SOURCE 0x00F0 ///< Texture env 4 source.
#define GPUREG_TEXENV4_OPERAND 0x00F1 ///< Texture env 4 operand.
#define GPUREG_TEXENV4_COMBINER 0x00F2 ///< Texture env 4 combiner.
#define GPUREG_TEXENV4_COLOR 0x00F3 ///< Texture env 4 color.
#define GPUREG_TEXENV4_SCALE 0x00F4 ///< Texture env 4 scale.
#define GPUREG_00F5 0x00F5 ///< Unknown.
#define GPUREG_00F6 0x00F6 ///< Unknown.
#define GPUREG_00F7 0x00F7 ///< Unknown.
#define GPUREG_TEXENV5_SOURCE 0x00F8 ///< Texture env 5 source.
#define GPUREG_TEXENV5_OPERAND 0x00F9 ///< Texture env 5 operand.
#define GPUREG_TEXENV5_COMBINER 0x00FA ///< Texture env 5 combiner.
#define GPUREG_TEXENV5_COLOR 0x00FB ///< Texture env 5 color.
#define GPUREG_TEXENV5_SCALE 0x00FC ///< Texture env 5 scale.
#define GPUREG_TEXENV_BUFFER_COLOR 0x00FD ///< Texture env buffer color.
#define GPUREG_00FE 0x00FE ///< Unknown.
#define GPUREG_00FF 0x00FF ///< Unknown.
///@}
///@name Framebuffer registers (0x100-0x13F)
///@{
#define GPUREG_COLOR_OPERATION 0x0100 ///< Configures fragment operation and blend mode.
#define GPUREG_BLEND_FUNC 0x0101 ///< Blend function configuration.
#define GPUREG_LOGIC_OP 0x0102 ///< Logical operator configuration.
#define GPUREG_BLEND_COLOR 0x0103 ///< Blend color.
#define GPUREG_FRAGOP_ALPHA_TEST 0x0104 ///< Alpha test configuration.
#define GPUREG_STENCIL_TEST 0x0105 ///< Stencil test configuration.
#define GPUREG_STENCIL_OP 0x0106 ///< Stencil test operation.
#define GPUREG_DEPTH_COLOR_MASK 0x0107 ///< Depth test and color mask configuration.
#define GPUREG_0108 0x0108 ///< Unknown.
#define GPUREG_0109 0x0109 ///< Unknown.
#define GPUREG_010A 0x010A ///< Unknown.
#define GPUREG_010B 0x010B ///< Unknown.
#define GPUREG_010C 0x010C ///< Unknown.
#define GPUREG_010D 0x010D ///< Unknown.
#define GPUREG_010E 0x010E ///< Unknown.
#define GPUREG_010F 0x010F ///< Unknown.
#define GPUREG_FRAMEBUFFER_INVALIDATE 0x0110 ///< Invalidates the frame buffer.
#define GPUREG_FRAMEBUFFER_FLUSH 0x0111 ///< Flushes the frame buffer.
#define GPUREG_COLORBUFFER_READ 0x0112 ///< Reads from the color buffer.
#define GPUREG_COLORBUFFER_WRITE 0x0113 ///< Writes to the color buffer.
#define GPUREG_DEPTHBUFFER_READ 0x0114 ///< Reads from the depth buffer.
#define GPUREG_DEPTHBUFFER_WRITE 0x0115 ///< Writes to the depth buffer.
#define GPUREG_DEPTHBUFFER_FORMAT 0x0116 ///< Depth buffer format.
#define GPUREG_COLORBUFFER_FORMAT 0x0117 ///< Color buffer format.
#define GPUREG_EARLYDEPTH_TEST2 0x0118 ///< Unknown.
#define GPUREG_0119 0x0119 ///< Unknown.
#define GPUREG_011A 0x011A ///< Unknown.
#define GPUREG_FRAMEBUFFER_BLOCK32 0x011B ///< Frame buffer block 32.
#define GPUREG_DEPTHBUFFER_LOC 0x011C ///< Depth buffer location.
#define GPUREG_COLORBUFFER_LOC 0x011D ///< Color buffer location.
#define GPUREG_FRAMEBUFFER_DIM 0x011E ///< Frame buffer dimensions.
#define GPUREG_011F 0x011F ///< Unknown.
#define GPUREG_GAS_LIGHT_XY 0x0120 ///< Unknown.
#define GPUREG_GAS_LIGHT_Z 0x0121 ///< Unknown.
#define GPUREG_GAS_LIGHT_Z_COLOR 0x0122 ///< Unknown.
#define GPUREG_GAS_LUT_INDEX 0x0123 ///< Unknown.
#define GPUREG_GAS_LUT_DATA 0x0124 ///< Unknown.
#define GPUREG_GAS_ACCMAX_FEEDBACK 0x0125 ///< Unknown.
#define GPUREG_GAS_DELTAZ_DEPTH 0x0126 ///< Unknown.
#define GPUREG_0127 0x0127 ///< Unknown.
#define GPUREG_0128 0x0128 ///< Unknown.
#define GPUREG_0129 0x0129 ///< Unknown.
#define GPUREG_012A 0x012A ///< Unknown.
#define GPUREG_012B 0x012B ///< Unknown.
#define GPUREG_012C 0x012C ///< Unknown.
#define GPUREG_012D 0x012D ///< Unknown.
#define GPUREG_012E 0x012E ///< Unknown.
#define GPUREG_012F 0x012F ///< Unknown.
#define GPUREG_FRAGOP_SHADOW 0x0130 ///< Unknown.
#define GPUREG_0131 0x0131 ///< Unknown.
#define GPUREG_0132 0x0132 ///< Unknown.
#define GPUREG_0133 0x0133 ///< Unknown.
#define GPUREG_0134 0x0134 ///< Unknown.
#define GPUREG_0135 0x0135 ///< Unknown.
#define GPUREG_0136 0x0136 ///< Unknown.
#define GPUREG_0137 0x0137 ///< Unknown.
#define GPUREG_0138 0x0138 ///< Unknown.
#define GPUREG_0139 0x0139 ///< Unknown.
#define GPUREG_013A 0x013A ///< Unknown.
#define GPUREG_013B 0x013B ///< Unknown.
#define GPUREG_013C 0x013C ///< Unknown.
#define GPUREG_013D 0x013D ///< Unknown.
#define GPUREG_013E 0x013E ///< Unknown.
#define GPUREG_013F 0x013F ///< Unknown.
///@}
///@name Fragment lighting registers (0x140-0x1FF)
///@{
#define GPUREG_LIGHT0_SPECULAR0 0x0140 ///< Light 0 specular lighting.
#define GPUREG_LIGHT0_SPECULAR1 0x0141 ///< Light 0 specular lighting.
#define GPUREG_LIGHT0_DIFFUSE 0x0142 ///< Light 0 diffuse lighting.
#define GPUREG_LIGHT0_AMBIENT 0x0143 ///< Light 0 ambient lighting.
#define GPUREG_LIGHT0_XY 0x0144 ///< Light 0 X and Y.
#define GPUREG_LIGHT0_Z 0x0145 ///< Light 0 Z.
#define GPUREG_LIGHT0_SPOTDIR_XY 0x0146 ///< Light 0 spotlight direction X and Y.
#define GPUREG_LIGHT0_SPOTDIR_Z 0x0147 ///< Light 0 spotlight direction Z.
#define GPUREG_0148 0x0148 ///< Unknown.
#define GPUREG_LIGHT0_CONFIG 0x0149 ///< Light 0 configuration.
#define GPUREG_LIGHT0_ATTENUATION_BIAS 0x014A ///< Light 0 attenuation bias.
#define GPUREG_LIGHT0_ATTENUATION_SCALE 0x014B ///< Light 0 attenuation scale.
#define GPUREG_014C 0x014C ///< Unknown.
#define GPUREG_014D 0x014D ///< Unknown.
#define GPUREG_014E 0x014E ///< Unknown.
#define GPUREG_014F 0x014F ///< Unknown.
#define GPUREG_LIGHT1_SPECULAR0 0x0150 ///< Light 1 specular lighting.
#define GPUREG_LIGHT1_SPECULAR1 0x0151 ///< Light 1 specular lighting.
#define GPUREG_LIGHT1_DIFFUSE 0x0152 ///< Light 1 diffuse lighting.
#define GPUREG_LIGHT1_AMBIENT 0x0153 ///< Light 1 ambient lighting.
#define GPUREG_LIGHT1_XY 0x0154 ///< Light 1 X and Y.
#define GPUREG_LIGHT1_Z 0x0155 ///< Light 1 Z.
#define GPUREG_LIGHT1_SPOTDIR_XY 0x0156 ///< Light 1 spotlight direction X and Y.
#define GPUREG_LIGHT1_SPOTDIR_Z 0x0157 ///< Light 1 spotlight direction Z.
#define GPUREG_0158 0x0158 ///< Unknown.
#define GPUREG_LIGHT1_CONFIG 0x0159 ///< Light 1 configuration.
#define GPUREG_LIGHT1_ATTENUATION_BIAS 0x015A ///< Light 1 attenuation bias.
#define GPUREG_LIGHT1_ATTENUATION_SCALE 0x015B ///< Light 1 attenuation scale.
#define GPUREG_015C 0x015C ///< Unknown.
#define GPUREG_015D 0x015D ///< Unknown.
#define GPUREG_015E 0x015E ///< Unknown.
#define GPUREG_015F 0x015F ///< Unknown.
#define GPUREG_LIGHT2_SPECULAR0 0x0160 ///< Light 2 specular lighting.
#define GPUREG_LIGHT2_SPECULAR1 0x0161 ///< Light 2 specular lighting.
#define GPUREG_LIGHT2_DIFFUSE 0x0162 ///< Light 2 diffuse lighting.
#define GPUREG_LIGHT2_AMBIENT 0x0163 ///< Light 2 ambient lighting.
#define GPUREG_LIGHT2_XY 0x0164 ///< Light 2 X and Y.
#define GPUREG_LIGHT2_Z 0x0165 ///< Light 2 Z.
#define GPUREG_LIGHT2_SPOTDIR_XY 0x0166 ///< Light 2 spotlight direction X and Y.
#define GPUREG_LIGHT2_SPOTDIR_Z 0x0167 ///< Light 2 spotlight direction Z.
#define GPUREG_0168 0x0168 ///< Unknown.
#define GPUREG_LIGHT2_CONFIG 0x0169 ///< Light 2 configuration.
#define GPUREG_LIGHT2_ATTENUATION_BIAS 0x016A ///< Light 2 attenuation bias.
#define GPUREG_LIGHT2_ATTENUATION_SCALE 0x016B ///< Light 2 attenuation scale.
#define GPUREG_016C 0x016C ///< Unknown.
#define GPUREG_016D 0x016D ///< Unknown.
#define GPUREG_016E 0x016E ///< Unknown.
#define GPUREG_016F 0x016F ///< Unknown.
#define GPUREG_LIGHT3_SPECULAR0 0x0170 ///< Light 3 specular lighting.
#define GPUREG_LIGHT3_SPECULAR1 0x0171 ///< Light 3 specular lighting.
#define GPUREG_LIGHT3_DIFFUSE 0x0172 ///< Light 3 diffuse lighting.
#define GPUREG_LIGHT3_AMBIENT 0x0173 ///< Light 3 ambient lighting.
#define GPUREG_LIGHT3_XY 0x0174 ///< Light 3 X and Y.
#define GPUREG_LIGHT3_Z 0x0175 ///< Light 3 Z.
#define GPUREG_LIGHT3_SPOTDIR_XY 0x0176 ///< Light 3 spotlight direction X and Y.
#define GPUREG_LIGHT3_SPOTDIR_Z 0x0177 ///< Light 3 spotlight direction Z.
#define GPUREG_0178 0x0178 ///< Unknown.
#define GPUREG_LIGHT3_CONFIG 0x0179 ///< Light 3 configuration.
#define GPUREG_LIGHT3_ATTENUATION_BIAS 0x017A ///< Light 3 attenuation bias.
#define GPUREG_LIGHT3_ATTENUATION_SCALE 0x017B ///< Light 3 attenuation scale.
#define GPUREG_017C 0x017C ///< Unknown.
#define GPUREG_017D 0x017D ///< Unknown.
#define GPUREG_017E 0x017E ///< Unknown.
#define GPUREG_017F 0x017F ///< Unknown.
#define GPUREG_LIGHT4_SPECULAR0 0x0180 ///< Light 4 specular lighting.
#define GPUREG_LIGHT4_SPECULAR1 0x0181 ///< Light 4 specular lighting.
#define GPUREG_LIGHT4_DIFFUSE 0x0182 ///< Light 4 diffuse lighting.
#define GPUREG_LIGHT4_AMBIENT 0x0183 ///< Light 4 ambient lighting.
#define GPUREG_LIGHT4_XY 0x0184 ///< Light 4 X and Y.
#define GPUREG_LIGHT4_Z 0x0185 ///< Light 4 Z.
#define GPUREG_LIGHT4_SPOTDIR_XY 0x0186 ///< Light 4 spotlight direction X and Y.
#define GPUREG_LIGHT4_SPOTDIR_Z 0x0187 ///< Light 4 spotlight direction Z.
#define GPUREG_0188 0x0188 ///< Unknown.
#define GPUREG_LIGHT4_CONFIG 0x0189 ///< Light 4 configuration.
#define GPUREG_LIGHT4_ATTENUATION_BIAS 0x018A ///< Light 4 attenuation bias.
#define GPUREG_LIGHT4_ATTENUATION_SCALE 0x018B ///< Light 4 attenuation scale.
#define GPUREG_018C 0x018C ///< Unknown.
#define GPUREG_018D 0x018D ///< Unknown.
#define GPUREG_018E 0x018E ///< Unknown.
#define GPUREG_018F 0x018F ///< Unknown.
#define GPUREG_LIGHT5_SPECULAR0 0x0190 ///< Light 5 specular lighting.
#define GPUREG_LIGHT5_SPECULAR1 0x0191 ///< Light 5 specular lighting.
#define GPUREG_LIGHT5_DIFFUSE 0x0192 ///< Light 5 diffuse lighting.
#define GPUREG_LIGHT5_AMBIENT 0x0193 ///< Light 5 ambient lighting.
#define GPUREG_LIGHT5_XY 0x0194 ///< Light 5 X and Y.
#define GPUREG_LIGHT5_Z 0x0195 ///< Light 5 Z.
#define GPUREG_LIGHT5_SPOTDIR_XY 0x0196 ///< Light 5 spotlight direction X and Y.
#define GPUREG_LIGHT5_SPOTDIR_Z 0x0197 ///< Light 5 spotlight direction Z.
#define GPUREG_0198 0x0198 ///< Unknown.
#define GPUREG_LIGHT5_CONFIG 0x0199 ///< Light 5 configuration.
#define GPUREG_LIGHT5_ATTENUATION_BIAS 0x019A ///< Light 5 attenuation bias.
#define GPUREG_LIGHT5_ATTENUATION_SCALE 0x019B ///< Light 5 attenuation scale.
#define GPUREG_019C 0x019C ///< Unknown.
#define GPUREG_019D 0x019D ///< Unknown.
#define GPUREG_019E 0x019E ///< Unknown.
#define GPUREG_019F 0x019F ///< Unknown.
#define GPUREG_LIGHT6_SPECULAR0 0x01A0 ///< Light 6 specular lighting.
#define GPUREG_LIGHT6_SPECULAR1 0x01A1 ///< Light 6 specular lighting.
#define GPUREG_LIGHT6_DIFFUSE 0x01A2 ///< Light 6 diffuse lighting.
#define GPUREG_LIGHT6_AMBIENT 0x01A3 ///< Light 6 ambient lighting.
#define GPUREG_LIGHT6_XY 0x01A4 ///< Light 6 X and Y.
#define GPUREG_LIGHT6_Z 0x01A5 ///< Light 6 Z.
#define GPUREG_LIGHT6_SPOTDIR_XY 0x01A6 ///< Light 6 spotlight direction X and Y.
#define GPUREG_LIGHT6_SPOTDIR_Z 0x01A7 ///< Light 6 spotlight direction Z.
#define GPUREG_01A8 0x01A8 ///< Unknown.
#define GPUREG_LIGHT6_CONFIG 0x01A9 ///< Light 6 configuration.
#define GPUREG_LIGHT6_ATTENUATION_BIAS 0x01AA ///< Light 6 attenuation bias.
#define GPUREG_LIGHT6_ATTENUATION_SCALE 0x01AB ///< Light 6 attenuation scale.
#define GPUREG_01AC 0x01AC ///< Unknown.
#define GPUREG_01AD 0x01AD ///< Unknown.
#define GPUREG_01AE 0x01AE ///< Unknown.
#define GPUREG_01AF 0x01AF ///< Unknown.
#define GPUREG_LIGHT7_SPECULAR0 0x01B0 ///< Light 7 specular lighting.
#define GPUREG_LIGHT7_SPECULAR1 0x01B1 ///< Light 7 specular lighting.
#define GPUREG_LIGHT7_DIFFUSE 0x01B2 ///< Light 7 diffuse lighting.
#define GPUREG_LIGHT7_AMBIENT 0x01B3 ///< Light 7 ambient lighting.
#define GPUREG_LIGHT7_XY 0x01B4 ///< Light 7 X and Y.
#define GPUREG_LIGHT7_Z 0x01B5 ///< Light 7 Z.
#define GPUREG_LIGHT7_SPOTDIR_XY 0x01B6 ///< Light 7 spotlight direction X and Y.
#define GPUREG_LIGHT7_SPOTDIR_Z 0x01B7 ///< Light 7 spotlight direction Z.
#define GPUREG_01B8 0x01B8 ///< Unknown.
#define GPUREG_LIGHT7_CONFIG 0x01B9 ///< Light 7 configuration.
#define GPUREG_LIGHT7_ATTENUATION_BIAS 0x01BA ///< Light 7 attenuation bias.
#define GPUREG_LIGHT7_ATTENUATION_SCALE 0x01BB ///< Light 7 attenuation scale.
#define GPUREG_01BC 0x01BC ///< Unknown.
#define GPUREG_01BD 0x01BD ///< Unknown.
#define GPUREG_01BE 0x01BE ///< Unknown.
#define GPUREG_01BF 0x01BF ///< Unknown.
#define GPUREG_LIGHTING_AMBIENT 0x01C0 ///< Ambient lighting.
#define GPUREG_01C1 0x01C1 ///< Unknown.
#define GPUREG_LIGHTING_NUM_LIGHTS 0x01C2 ///< Number of lights.
#define GPUREG_LIGHTING_CONFIG0 0x01C3 ///< Lighting configuration.
#define GPUREG_LIGHTING_CONFIG1 0x01C4 ///< Lighting configuration.
#define GPUREG_LIGHTING_LUT_INDEX 0x01C5 ///< LUT index.
#define GPUREG_LIGHTING_ENABLE1 0x01C6 ///< Lighting toggle.
#define GPUREG_01C7 0x01C7 ///< Unknown.
#define GPUREG_LIGHTING_LUT_DATA0 0x01C8 ///< LUT data 0.
#define GPUREG_LIGHTING_LUT_DATA1 0x01C9 ///< LUT data 1.
#define GPUREG_LIGHTING_LUT_DATA2 0x01CA ///< LUT data 2.
#define GPUREG_LIGHTING_LUT_DATA3 0x01CB ///< LUT data 3.
#define GPUREG_LIGHTING_LUT_DATA4 0x01CC ///< LUT data 4.
#define GPUREG_LIGHTING_LUT_DATA5 0x01CD ///< LUT data 5.
#define GPUREG_LIGHTING_LUT_DATA6 0x01CE ///< LUT data 6.
#define GPUREG_LIGHTING_LUT_DATA7 0x01CF ///< LUT data 7.
#define GPUREG_LIGHTING_LUTINPUT_ABS 0x01D0 ///< LUT input abs.
#define GPUREG_LIGHTING_LUTINPUT_SELECT 0x01D1 ///< LUT input selector.
#define GPUREG_LIGHTING_LUTINPUT_SCALE 0x01D2 ///< LUT input scale.
#define GPUREG_01D3 0x01D3 ///< Unknown.
#define GPUREG_01D4 0x01D4 ///< Unknown.
#define GPUREG_01D5 0x01D5 ///< Unknown.
#define GPUREG_01D6 0x01D6 ///< Unknown.
#define GPUREG_01D7 0x01D7 ///< Unknown.
#define GPUREG_01D8 0x01D8 ///< Unknown.
#define GPUREG_LIGHTING_LIGHT_PERMUTATION 0x01D9 ///< Light permutation.
#define GPUREG_01DA 0x01DA ///< Unknown.
#define GPUREG_01DB 0x01DB ///< Unknown.
#define GPUREG_01DC 0x01DC ///< Unknown.
#define GPUREG_01DD 0x01DD ///< Unknown.
#define GPUREG_01DE 0x01DE ///< Unknown.
#define GPUREG_01DF 0x01DF ///< Unknown.
#define GPUREG_01E0 0x01E0 ///< Unknown.
#define GPUREG_01E1 0x01E1 ///< Unknown.
#define GPUREG_01E2 0x01E2 ///< Unknown.
#define GPUREG_01E3 0x01E3 ///< Unknown.
#define GPUREG_01E4 0x01E4 ///< Unknown.
#define GPUREG_01E5 0x01E5 ///< Unknown.
#define GPUREG_01E6 0x01E6 ///< Unknown.
#define GPUREG_01E7 0x01E7 ///< Unknown.
#define GPUREG_01E8 0x01E8 ///< Unknown.
#define GPUREG_01E9 0x01E9 ///< Unknown.
#define GPUREG_01EA 0x01EA ///< Unknown.
#define GPUREG_01EB 0x01EB ///< Unknown.
#define GPUREG_01EC 0x01EC ///< Unknown.
#define GPUREG_01ED 0x01ED ///< Unknown.
#define GPUREG_01EE 0x01EE ///< Unknown.
#define GPUREG_01EF 0x01EF ///< Unknown.
#define GPUREG_01F0 0x01F0 ///< Unknown.
#define GPUREG_01F1 0x01F1 ///< Unknown.
#define GPUREG_01F2 0x01F2 ///< Unknown.
#define GPUREG_01F3 0x01F3 ///< Unknown.
#define GPUREG_01F4 0x01F4 ///< Unknown.
#define GPUREG_01F5 0x01F5 ///< Unknown.
#define GPUREG_01F6 0x01F6 ///< Unknown.
#define GPUREG_01F7 0x01F7 ///< Unknown.
#define GPUREG_01F8 0x01F8 ///< Unknown.
#define GPUREG_01F9 0x01F9 ///< Unknown.
#define GPUREG_01FA 0x01FA ///< Unknown.
#define GPUREG_01FB 0x01FB ///< Unknown.
#define GPUREG_01FC 0x01FC ///< Unknown.
#define GPUREG_01FD 0x01FD ///< Unknown.
#define GPUREG_01FE 0x01FE ///< Unknown.
#define GPUREG_01FF 0x01FF ///< Unknown.
///@}
///@name Geometry pipeline registers (0x200-0x27F)
///@{
#define GPUREG_ATTRIBBUFFERS_LOC 0x0200 ///< Attribute buffers location.
#define GPUREG_ATTRIBBUFFERS_FORMAT_LOW 0x0201 ///< Attribute buffers format low.
#define GPUREG_ATTRIBBUFFERS_FORMAT_HIGH 0x0202 ///< Attribute buffers format high.
#define GPUREG_ATTRIBBUFFER0_OFFSET 0x0203 ///< Attribute buffers 0 offset.
#define GPUREG_ATTRIBBUFFER0_CONFIG1 0x0204 ///< Attribute buffers 0 configuration.
#define GPUREG_ATTRIBBUFFER0_CONFIG2 0x0205 ///< Attribute buffers 0 configuration.
#define GPUREG_ATTRIBBUFFER1_OFFSET 0x0206 ///< Attribute buffers 1 offset.
#define GPUREG_ATTRIBBUFFER1_CONFIG1 0x0207 ///< Attribute buffers 1 configuration.
#define GPUREG_ATTRIBBUFFER1_CONFIG2 0x0208 ///< Attribute buffers 1 configuration.
#define GPUREG_ATTRIBBUFFER2_OFFSET 0x0209 ///< Attribute buffers 2 offset.
#define GPUREG_ATTRIBBUFFER2_CONFIG1 0x020A ///< Attribute buffers 2 configuration.
#define GPUREG_ATTRIBBUFFER2_CONFIG2 0x020B ///< Attribute buffers 2 configuration.
#define GPUREG_ATTRIBBUFFER3_OFFSET 0x020C ///< Attribute buffers 3 offset.
#define GPUREG_ATTRIBBUFFER3_CONFIG1 0x020D ///< Attribute buffers 3 configuration.
#define GPUREG_ATTRIBBUFFER3_CONFIG2 0x020E ///< Attribute buffers 3 configuration.
#define GPUREG_ATTRIBBUFFER4_OFFSET 0x020F ///< Attribute buffers 4 offset.
#define GPUREG_ATTRIBBUFFER4_CONFIG1 0x0210 ///< Attribute buffers 4 configuration.
#define GPUREG_ATTRIBBUFFER4_CONFIG2 0x0211 ///< Attribute buffers 4 configuration.
#define GPUREG_ATTRIBBUFFER5_OFFSET 0x0212 ///< Attribute buffers 5 offset.
#define GPUREG_ATTRIBBUFFER5_CONFIG1 0x0213 ///< Attribute buffers 5 configuration.
#define GPUREG_ATTRIBBUFFER5_CONFIG2 0x0214 ///< Attribute buffers 5 configuration.
#define GPUREG_ATTRIBBUFFER6_OFFSET 0x0215 ///< Attribute buffers 6 offset.
#define GPUREG_ATTRIBBUFFER6_CONFIG1 0x0216 ///< Attribute buffers 6 configuration.
#define GPUREG_ATTRIBBUFFER6_CONFIG2 0x0217 ///< Attribute buffers 6 configuration.
#define GPUREG_ATTRIBBUFFER7_OFFSET 0x0218 ///< Attribute buffers 7 offset.
#define GPUREG_ATTRIBBUFFER7_CONFIG1 0x0219 ///< Attribute buffers 7 configuration.
#define GPUREG_ATTRIBBUFFER7_CONFIG2 0x021A ///< Attribute buffers 7 configuration.
#define GPUREG_ATTRIBBUFFER8_OFFSET 0x021B ///< Attribute buffers 8 offset.
#define GPUREG_ATTRIBBUFFER8_CONFIG1 0x021C ///< Attribute buffers 8 configuration.
#define GPUREG_ATTRIBBUFFER8_CONFIG2 0x021D ///< Attribute buffers 8 configuration.
#define GPUREG_ATTRIBBUFFER9_OFFSET 0x021E ///< Attribute buffers 9 offset.
#define GPUREG_ATTRIBBUFFER9_CONFIG1 0x021F ///< Attribute buffers 9 configuration.
#define GPUREG_ATTRIBBUFFER9_CONFIG2 0x0220 ///< Attribute buffers 9 configuration.
#define GPUREG_ATTRIBBUFFERA_OFFSET 0x0221 ///< Attribute buffers A offset.
#define GPUREG_ATTRIBBUFFERA_CONFIG1 0x0222 ///< Attribute buffers A configuration.
#define GPUREG_ATTRIBBUFFERA_CONFIG2 0x0223 ///< Attribute buffers A configuration.
#define GPUREG_ATTRIBBUFFERB_OFFSET 0x0224 ///< Attribute buffers B offset.
#define GPUREG_ATTRIBBUFFERB_CONFIG1 0x0225 ///< Attribute buffers B configuration.
#define GPUREG_ATTRIBBUFFERB_CONFIG2 0x0226 ///< Attribute buffers B configuration.
#define GPUREG_INDEXBUFFER_CONFIG 0x0227 ///< Index buffer configuration.
#define GPUREG_NUMVERTICES 0x0228 ///< Number of vertices.
#define GPUREG_GEOSTAGE_CONFIG 0x0229 ///< Geometry stage configuration.
#define GPUREG_VERTEX_OFFSET 0x022A ///< Vertex offset.
#define GPUREG_022B 0x022B ///< Unknown.
#define GPUREG_022C 0x022C ///< Unknown.
#define GPUREG_POST_VERTEX_CACHE_NUM 0x022D ///< Unknown.
#define GPUREG_DRAWARRAYS 0x022E ///< Draw arrays trigger.
#define GPUREG_DRAWELEMENTS 0x022F ///< Draw arrays elements.
#define GPUREG_0230 0x0230 ///< Unknown.
#define GPUREG_VTX_FUNC 0x0231 ///< Unknown.
#define GPUREG_FIXEDATTRIB_INDEX 0x0232 ///< Fixed attribute index.
#define GPUREG_FIXEDATTRIB_DATA0 0x0233 ///< Fixed attribute data 0.
#define GPUREG_FIXEDATTRIB_DATA1 0x0234 ///< Fixed attribute data 1.
#define GPUREG_FIXEDATTRIB_DATA2 0x0235 ///< Fixed attribute data 2.
#define GPUREG_0236 0x0236 ///< Unknown.
#define GPUREG_0237 0x0237 ///< Unknown.
#define GPUREG_CMDBUF_SIZE0 0x0238 ///< Command buffer size 0.
#define GPUREG_CMDBUF_SIZE1 0x0239 ///< Command buffer size 1.
#define GPUREG_CMDBUF_ADDR0 0x023A ///< Command buffer address 0.
#define GPUREG_CMDBUF_ADDR1 0x023B ///< Command buffer address 1.
#define GPUREG_CMDBUF_JUMP0 0x023C ///< Command buffer jump 0.
#define GPUREG_CMDBUF_JUMP1 0x023D ///< Command buffer jump 1.
#define GPUREG_023E 0x023E ///< Unknown.
#define GPUREG_023F 0x023F ///< Unknown.
#define GPUREG_0240 0x0240 ///< Unknown.
#define GPUREG_0241 0x0241 ///< Unknown.
#define GPUREG_VSH_NUM_ATTR 0x0242 ///< Unknown.
#define GPUREG_0243 0x0243 ///< Unknown.
#define GPUREG_VSH_COM_MODE 0x0244 ///< Unknown.
#define GPUREG_START_DRAW_FUNC0 0x0245 ///< Unknown.
#define GPUREG_0246 0x0246 ///< Unknown.
#define GPUREG_0247 0x0247 ///< Unknown.
#define GPUREG_0248 0x0248 ///< Unknown.
#define GPUREG_0249 0x0249 ///< Unknown.
#define GPUREG_VSH_OUTMAP_TOTAL1 0x024A ///< Unknown.
#define GPUREG_024B 0x024B ///< Unknown.
#define GPUREG_024C 0x024C ///< Unknown.
#define GPUREG_024D 0x024D ///< Unknown.
#define GPUREG_024E 0x024E ///< Unknown.
#define GPUREG_024F 0x024F ///< Unknown.
#define GPUREG_0250 0x0250 ///< Unknown.
#define GPUREG_VSH_OUTMAP_TOTAL2 0x0251 ///< Unknown.
#define GPUREG_GSH_MISC0 0x0252 ///< Unknown.
#define GPUREG_GEOSTAGE_CONFIG2 0x0253 ///< Unknown.
#define GPUREG_GSH_MISC1 0x0254 ///< Unknown.
#define GPUREG_0255 0x0255 ///< Unknown.
#define GPUREG_0256 0x0256 ///< Unknown.
#define GPUREG_0257 0x0257 ///< Unknown.
#define GPUREG_0258 0x0258 ///< Unknown.
#define GPUREG_0259 0x0259 ///< Unknown.
#define GPUREG_025A 0x025A ///< Unknown.
#define GPUREG_025B 0x025B ///< Unknown.
#define GPUREG_025C 0x025C ///< Unknown.
#define GPUREG_025D 0x025D ///< Unknown.
#define GPUREG_PRIMITIVE_CONFIG 0x025E ///< Primitive configuration.
#define GPUREG_RESTART_PRIMITIVE 0x025F ///< Restart primitive flag.
#define GPUREG_0260 0x0260 ///< Unknown.
#define GPUREG_0261 0x0261 ///< Unknown.
#define GPUREG_0262 0x0262 ///< Unknown.
#define GPUREG_0263 0x0263 ///< Unknown.
#define GPUREG_0264 0x0264 ///< Unknown.
#define GPUREG_0265 0x0265 ///< Unknown.
#define GPUREG_0266 0x0266 ///< Unknown.
#define GPUREG_0267 0x0267 ///< Unknown.
#define GPUREG_0268 0x0268 ///< Unknown.
#define GPUREG_0269 0x0269 ///< Unknown.
#define GPUREG_026A 0x026A ///< Unknown.
#define GPUREG_026B 0x026B ///< Unknown.
#define GPUREG_026C 0x026C ///< Unknown.
#define GPUREG_026D 0x026D ///< Unknown.
#define GPUREG_026E 0x026E ///< Unknown.
#define GPUREG_026F 0x026F ///< Unknown.
#define GPUREG_0270 0x0270 ///< Unknown.
#define GPUREG_0271 0x0271 ///< Unknown.
#define GPUREG_0272 0x0272 ///< Unknown.
#define GPUREG_0273 0x0273 ///< Unknown.
#define GPUREG_0274 0x0274 ///< Unknown.
#define GPUREG_0275 0x0275 ///< Unknown.
#define GPUREG_0276 0x0276 ///< Unknown.
#define GPUREG_0277 0x0277 ///< Unknown.
#define GPUREG_0278 0x0278 ///< Unknown.
#define GPUREG_0279 0x0279 ///< Unknown.
#define GPUREG_027A 0x027A ///< Unknown.
#define GPUREG_027B 0x027B ///< Unknown.
#define GPUREG_027C 0x027C ///< Unknown.
#define GPUREG_027D 0x027D ///< Unknown.
#define GPUREG_027E 0x027E ///< Unknown.
#define GPUREG_027F 0x027F ///< Unknown.
///@}
///@name Geometry shader registers (0x280-0x2AF)
///@{
#define GPUREG_GSH_BOOLUNIFORM 0x0280 ///< Geometry shader bool uniforms.
#define GPUREG_GSH_INTUNIFORM_I0 0x0281 ///< Geometry shader integer uniform 0.
#define GPUREG_GSH_INTUNIFORM_I1 0x0282 ///< Geometry shader integer uniform 1.
#define GPUREG_GSH_INTUNIFORM_I2 0x0283 ///< Geometry shader integer uniform 2.
#define GPUREG_GSH_INTUNIFORM_I3 0x0284 ///< Geometry shader integer uniform 3.
#define GPUREG_0285 0x0285 ///< Unknown.
#define GPUREG_0286 0x0286 ///< Unknown.
#define GPUREG_0287 0x0287 ///< Unknown.
#define GPUREG_0288 0x0288 ///< Unknown.
#define GPUREG_GSH_INPUTBUFFER_CONFIG 0x0289 ///< Geometry shader input buffer configuration.
#define GPUREG_GSH_ENTRYPOINT 0x028A ///< Geometry shader entry point.
#define GPUREG_GSH_ATTRIBUTES_PERMUTATION_LOW 0x028B ///< Geometry shader attribute permutations low.
#define GPUREG_GSH_ATTRIBUTES_PERMUTATION_HIGH 0x028C ///< Geometry shader attribute permutations high.
#define GPUREG_GSH_OUTMAP_MASK 0x028D ///< Geometry shader output map mask.
#define GPUREG_028E 0x028E ///< Unknown.
#define GPUREG_GSH_CODETRANSFER_END 0x028F ///< Geometry shader code transfer end trigger.
#define GPUREG_GSH_FLOATUNIFORM_CONFIG 0x0290 ///< Geometry shader float uniform configuration.
#define GPUREG_GSH_FLOATUNIFORM_DATA 0x0291 ///< Geometry shader float uniform data.
#define GPUREG_0299 0x0299 ///< Unknown.
#define GPUREG_029A 0x029A ///< Unknown.
#define GPUREG_GSH_CODETRANSFER_CONFIG 0x029B ///< Geometry shader code transfer configuration.
#define GPUREG_GSH_CODETRANSFER_DATA 0x029C ///< Geometry shader code transfer data.
#define GPUREG_02A4 0x02A4 ///< Unknown.
#define GPUREG_GSH_OPDESCS_CONFIG 0x02A5 ///< Geometry shader operand description configuration.
#define GPUREG_GSH_OPDESCS_DATA 0x02A6 ///< Geometry shader operand description data.
#define GPUREG_02AE 0x02AE ///< Unknown.
#define GPUREG_02AF 0x02AF ///< Unknown.
///@}
///@name Vertex shader registers (0x2B0-0x2DF)
///@{
#define GPUREG_VSH_BOOLUNIFORM 0x02B0 ///< Vertex shader bool uniforms.
#define GPUREG_VSH_INTUNIFORM_I0 0x02B1 ///< Vertex shader integer uniform 0.
#define GPUREG_VSH_INTUNIFORM_I1 0x02B2 ///< Vertex shader integer uniform 1.
#define GPUREG_VSH_INTUNIFORM_I2 0x02B3 ///< Vertex shader integer uniform 2.
#define GPUREG_VSH_INTUNIFORM_I3 0x02B4 ///< Vertex shader integer uniform 3.
#define GPUREG_02B5 0x02B5 ///< Unknown.
#define GPUREG_02B6 0x02B6 ///< Unknown.
#define GPUREG_02B7 0x02B7 ///< Unknown.
#define GPUREG_02B8 0x02B8 ///< Unknown.
#define GPUREG_VSH_INPUTBUFFER_CONFIG 0x02B9 ///< Vertex shader input buffer configuration.
#define GPUREG_VSH_ENTRYPOINT 0x02BA ///< Vertex shader entry point.
#define GPUREG_VSH_ATTRIBUTES_PERMUTATION_LOW 0x02BB ///< Vertex shader attribute permutations low.
#define GPUREG_VSH_ATTRIBUTES_PERMUTATION_HIGH 0x02BC ///< Vertex shader attribute permutations high.
#define GPUREG_VSH_OUTMAP_MASK 0x02BD ///< Vertex shader output map mask.
#define GPUREG_02BE 0x02BE ///< Unknown.
#define GPUREG_VSH_CODETRANSFER_END 0x02BF ///< Vertex shader code transfer end trigger.
#define GPUREG_VSH_FLOATUNIFORM_CONFIG 0x02C0 ///< Vertex shader float uniform configuration.
#define GPUREG_VSH_FLOATUNIFORM_DATA 0x02C1 ///< Vertex shader float uniform data.
#define GPUREG_02C9 0x02C9 ///< Unknown.
#define GPUREG_02CA 0x02CA ///< Unknown.
#define GPUREG_VSH_CODETRANSFER_CONFIG 0x02CB ///< Vertex shader code transfer configuration.
#define GPUREG_VSH_CODETRANSFER_DATA 0x02CC ///< Vertex shader code transfer data.
#define GPUREG_02D4 0x02D4 ///< Unknown.
#define GPUREG_VSH_OPDESCS_CONFIG 0x02D5 ///< Vertex shader operand description configuration.
#define GPUREG_VSH_OPDESCS_DATA 0x02D6 ///< Vertex shader operand description data.
#define GPUREG_02DE 0x02DE ///< Unknown.
#define GPUREG_02DF 0x02DF ///< Unknown.
///@}
///@name Unknown registers (0x2E0-0x2FF)
///@{
#define GPUREG_02E0 0x02E0 ///< Unknown.
#define GPUREG_02E1 0x02E1 ///< Unknown.
#define GPUREG_02E2 0x02E2 ///< Unknown.
#define GPUREG_02E3 0x02E3 ///< Unknown.
#define GPUREG_02E4 0x02E4 ///< Unknown.
#define GPUREG_02E5 0x02E5 ///< Unknown.
#define GPUREG_02E6 0x02E6 ///< Unknown.
#define GPUREG_02E7 0x02E7 ///< Unknown.
#define GPUREG_02E8 0x02E8 ///< Unknown.
#define GPUREG_02E9 0x02E9 ///< Unknown.
#define GPUREG_02EA 0x02EA ///< Unknown.
#define GPUREG_02EB 0x02EB ///< Unknown.
#define GPUREG_02EC 0x02EC ///< Unknown.
#define GPUREG_02ED 0x02ED ///< Unknown.
#define GPUREG_02EE 0x02EE ///< Unknown.
#define GPUREG_02EF 0x02EF ///< Unknown.
#define GPUREG_02F0 0x02F0 ///< Unknown.
#define GPUREG_02F1 0x02F1 ///< Unknown.
#define GPUREG_02F2 0x02F2 ///< Unknown.
#define GPUREG_02F3 0x02F3 ///< Unknown.
#define GPUREG_02F4 0x02F4 ///< Unknown.
#define GPUREG_02F5 0x02F5 ///< Unknown.
#define GPUREG_02F6 0x02F6 ///< Unknown.
#define GPUREG_02F7 0x02F7 ///< Unknown.
#define GPUREG_02F8 0x02F8 ///< Unknown.
#define GPUREG_02F9 0x02F9 ///< Unknown.
#define GPUREG_02FA 0x02FA ///< Unknown.
#define GPUREG_02FB 0x02FB ///< Unknown.
#define GPUREG_02FC 0x02FC ///< Unknown.
#define GPUREG_02FD 0x02FD ///< Unknown.
#define GPUREG_02FE 0x02FE ///< Unknown.
#define GPUREG_02FF 0x02FF ///< Unknown.
///@}

View File

@ -0,0 +1,41 @@
#pragma once
#include "types.h"
#include "mem_map.h"
#define GX_REGS_BASE (IO_MEM_ARM11_ONLY + 0x200000)
#define REG_GX_GPU_CLK *((vu32*)(GX_REGS_BASE + 0x0004)) // ?
// PSC (memory fill) regs.
#define REG_GX_PSC_FILL0_S_ADDR *((vu32*)(GX_REGS_BASE + 0x0010)) // Start address
#define REG_GX_PSC_FILL0_E_ADDR *((vu32*)(GX_REGS_BASE + 0x0014)) // End address
#define REG_GX_PSC_FILL0_VAL *((vu32*)(GX_REGS_BASE + 0x0018)) // Fill value
#define REG_GX_PSC_FILL0_CNT *((vu32*)(GX_REGS_BASE + 0x001C))
#define REG_GX_PSC_FILL1_S_ADDR *((vu32*)(GX_REGS_BASE + 0x0020))
#define REG_GX_PSC_FILL1_E_ADDR *((vu32*)(GX_REGS_BASE + 0x0024))
#define REG_GX_PSC_FILL1_VAL *((vu32*)(GX_REGS_BASE + 0x0028))
#define REG_GX_PSC_FILL1_CNT *((vu32*)(GX_REGS_BASE + 0x002C))
#define REG_GX_PSC_VRAM *((vu32*)(GX_REGS_BASE + 0x0030)) // gsp mudule only changes bit 8-11.
#define REG_GX_PSC_STAT *((vu32*)(GX_REGS_BASE + 0x0034))
// PDC0/1 regs see lcd.h.
// PPF (transfer engine) regs.
#define REG_GX_PPF_IN_ADDR *((vu32*)(GX_REGS_BASE + 0x0C00))
#define REG_GX_PPF_OUT_ADDR *((vu32*)(GX_REGS_BASE + 0x0C04))
#define REG_GX_PPF_DT_OUTDIM *((vu32*)(GX_REGS_BASE + 0x0C08)) // Display transfer output dimensions.
#define REG_GX_PPF_DT_INDIM *((vu32*)(GX_REGS_BASE + 0x0C0C)) // Display transfer input dimensions.
#define REG_GX_PPF_FlAGS *((vu32*)(GX_REGS_BASE + 0x0C10))
#define REG_GX_PPF_UNK14 *((vu32*)(GX_REGS_BASE + 0x0C14)) // Transfer interval?
#define REG_GX_PPF_CNT *((vu32*)(GX_REGS_BASE + 0x0C18))
#define REG_GX_PPF_IRQ_POS *((vu32*)(GX_REGS_BASE + 0x0C1C)) // ?
#define REG_GX_PPF_LEN *((vu32*)(GX_REGS_BASE + 0x0C20)) // Texture copy size in bytes.
#define REG_GX_PPF_TC_INDIM *((vu32*)(GX_REGS_BASE + 0x0C24)) // Texture copy input width and gap in 16 byte units.
#define REG_GX_PPF_TC_OUTDIM *((vu32*)(GX_REGS_BASE + 0x0C28)) // Texture copy output width and gap in 16 byte units.
// P3D (GPU internal) regs. See gpu_regs.h.
#define REG_GX_P3D(reg) *((vu32*)(GX_REGS_BASE + 0x1000 + ((reg) * 4)))

View File

@ -0,0 +1,81 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2018 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
//////////////////////////////////
// HASH //
//////////////////////////////////
#define HASH_ENABLE (1u) // Also used as busy flag
#define HASH_FINAL_ROUND (1u<<1)
#define HASH_IN_DMA_ENABLE (1u<<2) // Without this NDMA startup is never fires
#define HASH_INPUT_BIG (1u<<3)
#define HASH_INPUT_LITTLE (0u)
#define HASH_OUTPUT_BIG (HASH_INPUT_BIG)
#define HASH_OUTPUT_LITTLE (HASH_INPUT_LITTLE)
#define HASH_MODE_256 (0u)
#define HASH_MODE_224 (1u<<4)
#define HASH_MODE_1 (2u<<4)
#define HASH_MODE_MASK (HASH_MODE_1 | HASH_MODE_224 | HASH_MODE_256)
/**
* @brief Sets input mode, endianess and starts the hash operation.
*
* @param[in] params Mode and input endianess bitmask.
*/
void HASH_start(u8 params);
/**
* @brief Hashes the data pointed to.
*
* @param[in] data Pointer to data to hash.
* @param[in] size Size of the data to hash.
*/
void HASH_update(const u32 *data, u32 size);
/**
* @brief Generates the final hash.
*
* @param hash Pointer to memory to copy the hash to.
* @param[in] endianess Endianess bitmask for the hash.
*/
void HASH_finish(u32 *const hash, u8 endianess);
/**
* @brief Returns the current HASH engine state.
*
* @param out Pointer to memory to copy the state to.
*/
void HASH_getState(u32 *const out);
/**
* @brief Hashes a single block of data and outputs the hash.
*
* @param[in] data Pointer to data to hash.
* @param[in] size Size of the data to hash.
* @param hash Pointer to memory to copy the hash to.
* @param[in] params Mode and input endianess bitmask.
* @param[in] hashEndianess Endianess bitmask for the hash.
*/
void hash(const u32 *data, u32 size, u32 *const hash, u8 params, u8 hashEndianess);

View File

@ -0,0 +1,105 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Based on code from https://github.com/smealum/ctrulib
*/
#include "types.h"
#include "mem_map.h"
#define HID_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x46000)
#define REG_HID_PAD (*((vu16*)(HID_REGS_BASE + 0x0)) ^ 0xFFFFu)
#define REG_HID_PADCNT *((vu16*)(HID_REGS_BASE + 0x2))
enum
{
KEY_A = 1u<<0, // A
KEY_B = 1u<<1, // B
KEY_SELECT = 1u<<2, // Select
KEY_START = 1u<<3, // Start
KEY_DRIGHT = 1u<<4, // D-Pad Right
KEY_DLEFT = 1u<<5, // D-Pad Left
KEY_DUP = 1u<<6, // D-Pad Up
KEY_DDOWN = 1u<<7, // D-Pad Down
KEY_R = 1u<<8, // R
KEY_L = 1u<<9, // L
KEY_X = 1u<<10, // X
KEY_Y = 1u<<11, // Y
KEY_ZL = 1u<<14, // ZL (New 3DS only)
KEY_ZR = 1u<<15, // ZR (New 3DS only)
KEY_TOUCH = 1u<<20, // Touch (Not actually provided by HID)
KEY_CSTICK_RIGHT = 1u<<24, // C-Stick Right (New 3DS only)
KEY_CSTICK_LEFT = 1u<<25, // C-Stick Left (New 3DS only)
KEY_CSTICK_UP = 1u<<26, // C-Stick Up (New 3DS only)
KEY_CSTICK_DOWN = 1u<<27, // C-Stick Down (New 3DS only)
KEY_CPAD_RIGHT = 1u<<28, // Circle Pad Right
KEY_CPAD_LEFT = 1u<<29, // Circle Pad Left
KEY_CPAD_UP = 1u<<30, // Circle Pad Up
KEY_CPAD_DOWN = 1u<<31, // Circle Pad Down
// Generic catch-all directions
KEY_UP = KEY_DUP | KEY_CPAD_UP, // D-Pad Up or Circle Pad Up
KEY_DOWN = KEY_DDOWN | KEY_CPAD_DOWN, // D-Pad Down or Circle Pad Down
KEY_LEFT = KEY_DLEFT | KEY_CPAD_LEFT, // D-Pad Left or Circle Pad Left
KEY_RIGHT = KEY_DRIGHT | KEY_CPAD_RIGHT, // D-Pad Right or Circle Pad Right
// Masks
KEY_DPAD_MASK = KEY_DDOWN | KEY_DUP | KEY_DLEFT | KEY_DRIGHT,
KEY_CSTICK_MASK = KEY_CSTICK_DOWN | KEY_CSTICK_UP | KEY_CSTICK_LEFT | KEY_CSTICK_RIGHT,
KEY_CPAD_MASK = KEY_CPAD_DOWN | KEY_CPAD_UP | KEY_CPAD_LEFT | KEY_CPAD_RIGHT
};
// Extra keys use with hidGetExtraKeys()
enum
{
KEY_POWER = 1u<<0,
KEY_POWER_HELD = 1u<<1,
KEY_HOME = 1u<<2, // Auto clears on release
KEY_WIFI = 1u<<3,
KEY_SHELL = 1u<<4, // Auto clears on open
KEY_BAT_CHARGING = 1u<<5, // Auto clears when charging stops
KEY_VOL_SLIDER = 1u<<6
};
typedef struct
{
u16 x;
u16 y;
} TouchPos;
typedef struct
{
s16 x;
s16 y;
} CpadPos;
void hidInit(void);
void hidScanInput(void);
u32 hidKeysHeld(void);
u32 hidKeysDown(void);
u32 hidKeysUp(void);
const TouchPos* hidGetTouchPosPtr(void);
const CpadPos* hidGetCpadPosPtr(void);
u32 hidGetExtraKeys(u32 clearMask);

View File

@ -0,0 +1,145 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#define I2C1_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x61000)
#define REG_I2C1_DATA *((vu8* )(I2C1_REGS_BASE + 0x0))
#define REG_I2C1_CNT *((vu8* )(I2C1_REGS_BASE + 0x1))
#define REG_I2C1_CNTEX *((vu16*)(I2C1_REGS_BASE + 0x2))
#define REG_I2C1_SCL *((vu16*)(I2C1_REGS_BASE + 0x4))
#define I2C2_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x44000)
#define REG_I2C2_DATA *((vu8* )(I2C2_REGS_BASE + 0x0))
#define REG_I2C2_CNT *((vu8* )(I2C2_REGS_BASE + 0x1))
#define REG_I2C2_CNTEX *((vu16*)(I2C2_REGS_BASE + 0x2))
#define REG_I2C2_SCL *((vu16*)(I2C2_REGS_BASE + 0x4))
#define I2C3_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x48000)
#define REG_I2C3_DATA *((vu8* )(I2C3_REGS_BASE + 0x0))
#define REG_I2C3_CNT *((vu8* )(I2C3_REGS_BASE + 0x1))
#define REG_I2C3_CNTEX *((vu16*)(I2C3_REGS_BASE + 0x2))
#define REG_I2C3_SCL *((vu16*)(I2C3_REGS_BASE + 0x4))
// REG_I2C_CNT
#define I2C_STOP (1u)
#define I2C_START (1u<<1)
#define I2C_ERROR (1u<<2)
#define I2C_ACK (1u<<4)
#define I2C_DIR_WRITE (0u)
#define I2C_DIR_READ (1u<<5)
#define I2C_IRQ_ENABLE (1u<<6)
#define I2C_ENABLE (1u<<7)
// REG_I2C_CNTEX
#define I2C_SCL_STATE (1u) // Read-only SCL line state?
#define I2C_CLK_STRETCH (1u<<1) // Enables clock stretching
#define I2C_UNK_CNTEX15 (1u<<15) // "LGCY" Legacy related?
// REG_I2C_SCL
#define I2C_DELAYS(high, low) ((high)<<8 | (low)) // "PRD" TODO: How long and when does it delay?
typedef enum
{
I2C_DEV_TWL_MCU = 0u, // DSi mode MCU
I2C_DEV_CAMERA1 = 1u, // Internal self-facing camera
I2C_DEV_CAMERA2 = 2u, // External right camera
I2C_DEV_CTR_MCU = 3u,
I2C_DEV_CAMERA3 = 4u, // External left camera
I2C_DEV_LCD0 = 5u, // Upper LCD
I2C_DEV_LCD1 = 6u, // Lower LCD
I2C_DEV_UNK7 = 7u, // Debug?
I2C_DEV_UNK8 = 8u, // Debug?
I2C_DEV_UNK9 = 9u, // HID debug?
I2C_DEV_GYRO_OLD = 10u, // Old 3DS only?
I2C_DEV_GYRO_NEW = 11u, // New 3DS only?
I2C_DEV_UNK12 = 12u, // HID "DebugPad"?
I2C_DEV_IR = 13u, // Infrared (IrDA)
I2C_DEV_EEPROM = 14u, // Dev unit only?
I2C_DEV_NFC = 15u,
I2C_DEV_QTM = 16u, // IO expander chip (New 3DS only)
I2C_DEV_N3DS_HID = 17u // C-Stick and ZL/ZR buttons
} I2cDevice;
/**
* @brief Initializes the I2C buses. Call this only once.
*/
void I2C_init(void);
/**
* @brief Reads data from a I2C register to a buffer.
*
* @param[in] devId The device ID. Use the enum above.
* @param[in] regAddr The register address.
* @param out The output buffer pointer.
* @param[in] size The read size.
*
* @return Returns true on success and false on failure.
*/
bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size);
/**
* @brief Writes a buffer to a I2C register.
*
* @param[in] devId The device ID. Use the enum above.
* @param[in] regAddr The register address.
* @param[in] in The input buffer pointer.
* @param[in] size The write size.
*
* @return Returns true on success and false on failure.
*/
bool I2C_writeRegBuf(I2cDevice devId, u8 regAddr, const u8 *in, u32 size);
/**
* @brief Reads a byte from a I2C register.
*
* @param[in] devId The device ID. Use the enum above.
* @param[in] regAddr The register address.
*
* @return Returns the value read on success otherwise 0xFF.
*/
u8 I2C_readReg(I2cDevice devId, u8 regAddr);
/**
* @brief Writes a byte to a I2C register.
*
* @param[in] devId The device ID. Use the enum above.
* @param[in] regAddr The register address.
* @param[in] data The data to write.
*
* @return Returns true on success and false on failure.
*/
bool I2C_writeReg(I2cDevice devId, u8 regAddr, u8 data);
/**
* @brief Writes a byte to a I2C register without interrupts.
*
* @param[in] devId The device ID. Use the enum above.
* @param[in] regAddr The register address.
* @param[in] data The data to write.
*
* @return Returns true on success and false on failure.
*/
bool I2C_writeRegIntSafe(I2cDevice devId, u8 regAddr, u8 data);

View File

@ -0,0 +1,236 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#include "mem_map.h"
#include "arm.h"
// Most register names from: https://github.com/torvalds/linux/blob/master/include/linux/irqchip/arm-gic.h
#define GIC_CPU_REGS_BASE (MPCORE_PRIV_REG_BASE + 0x100)
#define REG_GIC_CPU_CTRL *(( vu32*)(GIC_CPU_REGS_BASE + 0x00)) // Control Register.
#define REG_GIC_CPU_PRIMASK *(( vu32*)(GIC_CPU_REGS_BASE + 0x04)) // Priority Mask Register.
#define REG_GIC_CPU_BINPOINT *(( vu32*)(GIC_CPU_REGS_BASE + 0x08)) // Binary Point Register.
#define REG_GIC_CPU_INTACK *((const vu32*)(GIC_CPU_REGS_BASE + 0x0C)) // Interrupt Acknowledge Register.
#define REG_GIC_CPU_EOI *(( vu32*)(GIC_CPU_REGS_BASE + 0x10)) // End of Interrupt Register.
#define REG_GIC_CPU_RUNNINGPRI *((const vu32*)(GIC_CPU_REGS_BASE + 0x14)) // Running Priority Register.
#define REG_GIC_CPU_HIGHPRI *((const vu32*)(GIC_CPU_REGS_BASE + 0x18)) // Highest Pending Interrupt Register.
#define GIC_DIST_REGS_BASE (MPCORE_PRIV_REG_BASE + 0x1000)
#define REG_GIC_DIST_CTRL *(( vu32*)(GIC_DIST_REGS_BASE + 0x000)) // Interrupt Distributor Control Register.
#define REG_GIC_DIST_CTR *((const vu32*)(GIC_DIST_REGS_BASE + 0x004)) // Interrupt Controller Type Register.
#define REGs_GIC_DIST_ENABLE_SET (( vu32*)(GIC_DIST_REGS_BASE + 0x100)) // Interrupt Enable set Registers.
#define REGs_GIC_DIST_ENABLE_CLEAR (( vu32*)(GIC_DIST_REGS_BASE + 0x180)) // Interrupt Enable clear Registers.
#define REGs_GIC_DIST_PENDING_SET (( vu32*)(GIC_DIST_REGS_BASE + 0x200)) // Interrupt Pending set Registers.
#define REGs_GIC_DIST_PENDING_CLEAR (( vu32*)(GIC_DIST_REGS_BASE + 0x280)) // Interrupt Pending clear Registers.
#define REGs_GIC_DIST_ACTIVE_SET ((const vu32*)(GIC_DIST_REGS_BASE + 0x300)) // Interrupt Active Bit Registers.
#define REGs_GIC_DIST_PRI (( vu32*)(GIC_DIST_REGS_BASE + 0x400)) // Interrupt Priority Registers.
#define REGs_GIC_DIST_TARGET (( vu32*)(GIC_DIST_REGS_BASE + 0x800)) // Interrupt CPU targets Registers.
#define REGs_GIC_DIST_CONFIG (( vu32*)(GIC_DIST_REGS_BASE + 0xC00)) // Interrupt Configuration Registers.
#define REGs_GIC_DIST_LINE_LEVEL ((const vu32*)(GIC_DIST_REGS_BASE + 0xD00)) // Interrupt Line Level Registers.
#define REG_GIC_DIST_SOFTINT *(( vu32*)(GIC_DIST_REGS_BASE + 0xF00)) // Software Interrupt Register.
#define REG_GIC_DIST_PERIPH_IDENT0 *((const vu32*)(GIC_DIST_REGS_BASE + 0xFE0)) // Periphal Identification Register 0.
#define REG_GIC_DIST_PERIPH_IDENT1 *((const vu32*)(GIC_DIST_REGS_BASE + 0xFE4)) // Periphal Identification Register 1.
#define REG_GIC_DIST_PERIPH_IDENT2 *((const vu32*)(GIC_DIST_REGS_BASE + 0xFE8)) // Periphal Identification Register 2.
#define REG_GIC_DIST_PERIPH_IDENT3 *((const vu32*)(GIC_DIST_REGS_BASE + 0xFEC)) // Periphal Identification Register 3.
#define REG_GIC_DIST_PRIMECELL0 *((const vu32*)(GIC_DIST_REGS_BASE + 0xFF0)) // PrimeCell Identification Register 0.
#define REG_GIC_DIST_PRIMECELL1 *((const vu32*)(GIC_DIST_REGS_BASE + 0xFF4)) // PrimeCell Identification Register 0.
#define REG_GIC_DIST_PRIMECELL2 *((const vu32*)(GIC_DIST_REGS_BASE + 0xFF8)) // PrimeCell Identification Register 0.
#define REG_GIC_DIST_PRIMECELL3 *((const vu32*)(GIC_DIST_REGS_BASE + 0xFFC)) // PrimeCell Identification Register 0.
typedef enum
{
IRQ_IPI0 = 0u,
IRQ_IPI1 = 1u,
IRQ_IPI2 = 2u,
IRQ_IPI3 = 3u,
IRQ_IPI4 = 4u,
IRQ_IPI5 = 5u,
IRQ_IPI6 = 6u,
IRQ_IPI7 = 7u,
IRQ_IPI8 = 8u,
IRQ_IPI9 = 9u,
IRQ_IPI10 = 10u,
IRQ_IPI11 = 11u,
IRQ_IPI12 = 12u,
IRQ_IPI13 = 13u,
IRQ_IPI14 = 14u,
IRQ_IPI15 = 15u,
IRQ_TIMER = 29u, // MPCore timer.
IRQ_WATCHDOG = 30u, // MPCore watchdog.
IRQ_SPI2 = 36u, // SPI bus 2 interrupt status update.
IRQ_UART = 37u, // New3DS-only UART?
IRQ_PSC0 = 40u,
IRQ_PSC1 = 41u,
IRQ_PDC0 = 42u, // PDC0 topscreen H-/VBlank and errors.
IRQ_PDC1 = 43u, // PDC1 bottom screen H-/VBlank and errors.
IRQ_PPF = 44u,
IRQ_P3D = 45u,
IRQ_CDMA_EVENT0 = 48u, // Old3DS CDMA.
IRQ_CDMA_EVENT1 = 49u, // Old3DS CDMA.
IRQ_CDMA_EVENT2 = 50u, // Old3DS CDMA.
IRQ_CDMA_EVENT3 = 51u, // Old3DS CDMA.
IRQ_CDMA_EVENT4 = 52u, // Old3DS CDMA.
IRQ_CDMA_EVENT5 = 53u, // Old3DS CDMA.
IRQ_CDMA_EVENT6 = 54u, // Old3DS CDMA.
IRQ_CDMA_EVENT7 = 55u, // Old3DS CDMA.
IRQ_CDMA_EVENT8 = 56u, // Old3DS CDMA.
IRQ_CDMA_FAULT = 57u, // Old3DS CDMA.
IRQ_CDMA2_EVENT = 58u, // New3DS-only CDMA event 0-31.
IRQ_CDMA2_FAULT = 59u, // New3DS-only CDMA.
IRQ_SDIO2 = 64u, // SDIO2 controller (WiFi).
IRQ_SDIO2_IRQ = 65u, // SDIO2 IRQ pin (WiFi).
IRQ_SDIO3 = 66u, // SDIO3 controller.
IRQ_SDIO3_IRQ = 67u, // SDIO3 IRQ pin.
IRQ_NTRCARD = 68u, // NTRCARD controller.
IRQ_L2B1 = 69u, // New3DS-only first L2B converter.
IRQ_L2B2 = 70u, // New3DS-only second L2B converter.
IRQ_CAM1 = 72u, // Camera 1 (DSi).
IRQ_CAM2 = 73u, // Camera 2 (left eye).
IRQ_DSP = 74u,
IRQ_Y2R1 = 75u,
IRQ_LGYFB_BOT = 76u, // Legacy framebuffer bottom screen.
IRQ_LGYFB_TOP = 77u, // Legacy framebuffer top screen.
IRQ_Y2R2 = 78u, // New3DS-only.
IRQ_G1 = 79u, // New3DS-only Hantro G1 decoder.
IRQ_PXI_SYNC = 80u,
IRQ_PXI_SYNC2 = 81u,
IRQ_PXI_NOT_FULL = 82u,
IRQ_PXI_NOT_EMPTY = 83u,
IRQ_I2C1 = 84u,
IRQ_I2C2 = 85u,
IRQ_SPI3 = 86u, // SPI bus 3 interrupt status update.
IRQ_SPI1 = 87u, // SPI bus 1 interrupt status update.
IRQ_PDN = 88u,
IRQ_LGY_SLEEP = 89u, // Triggers if legacy mode enters sleep.
IRQ_MIC = 90u,
IRQ_HID_PADCNT = 91u,
IRQ_I2C3 = 92u,
IRQ_DS_WIFI = 95u,
IRQ_GPIO_1_2_HIGH = 96u,
IRQ_GPIO_1_2_LOW = 98u,
IRQ_GPIO_1_1 = 99u,
IRQ_GPIO_2_0 = 100u,
IRQ_GPIO_2_2 = 102u,
IRQ_GPIO_3_0 = 104u,
IRQ_GPIO_3_1 = 105u,
IRQ_GPIO_3_2 = 106u,
IRQ_GPIO_3_3 = 107u,
IRQ_GPIO_3_4 = 108u,
IRQ_GPIO_3_5 = 109u,
IRQ_GPIO_3_6 = 110u,
IRQ_GPIO_3_7 = 111u,
IRQ_GPIO_3_8 = 112u,
IRQ_GPIO_3_9 = 113u,
IRQ_GPIO_3_10 = 114u,
IRQ_GPIO_3_11 = 115u,
IRQ_GAMECARD_OFF = 116u, // Gamecard poweroff.
IRQ_GAMECARD_INS = 117u, // Gamecard inserted.
IRQ_L2C = 118u, // New3DS-only L2C-310 Level 2 Cache Controller.
IRQ_UNK119 = 119u,
IRQ_PERF_MONITOR0 = 120u, // Core 0 performance monitor. Triggers on any counter overflow.
IRQ_PERF_MONITOR1 = 121u, // Core 1 performance monitor. Triggers on any counter overflow.
IRQ_PERF_MONITOR2 = 122u, // Unconfirmed. Core 2 performance monitor. Triggers on any counter overflow.
IRQ_PERF_MONITOR3 = 123u, // Unconfirmed. Core 3 performance monitor. Triggers on any counter overflow.
// Aliases
IRQ_SHELL_OPENED = IRQ_GPIO_1_2_HIGH,
IRQ_SHELL_CLOSED = IRQ_GPIO_1_2_LOW, // Triggers on GPIO_1_2 low.
IRQ_TOUCHSCREEN = IRQ_GPIO_1_1, // Triggers on touchscreen pen down.
IRQ_HEADPH_JACK = IRQ_GPIO_2_0, // Headphone jack. Triggers on both plugging in and out?
IRQ_CTR_MCU = IRQ_GPIO_3_9 // Various MCU events trigger this. See MCU interrupt mask.
} Interrupt;
// IRQ interrupt service routine type.
// intSource: bit 10-12 CPU source ID (0 except for interrupt ID 0-15),
// bit 0-9 interrupt ID
typedef void (*IrqIsr)(u32 intSource);
/**
* @brief Initializes the generic interrupt controller.
*/
void IRQ_init(void);
/**
* @brief Registers a interrupt service routine and enables the specified interrupt.
*
* @param[in] id The interrupt ID. Must be <128.
* @param[in] prio The priority. 0 = highest, 14 = lowest, 15 = disabled.
* @param[in] cpuMask The CPU mask. Each of the 4 bits stands for 1 core.
* 0 means current CPU.
* @param[in] isr The interrupt service routine to call.
*/
void IRQ_registerIsr(Interrupt id, u8 prio, u8 cpuMask, IrqIsr isr);
/**
* @brief Reenables a previously disabled but registered interrupt.
*
* @param[in] id The interrupt ID. Must be <128.
*/
void IRQ_enable(Interrupt id);
/**
* @brief Disables a previously registered interrupt temporarily.
*
* @param[in] id The interrupt ID. Must be <128.
*/
void IRQ_disable(Interrupt id);
/**
* @brief Triggers a software interrupt for the specified CPUs.
*
* @param[in] id The interrupt ID. Must be <16.
* @param[in] cpuMask The CPU mask. Each of the 4 bits stands for 1 core.
*/
void IRQ_softwareInterrupt(Interrupt id, u8 cpuMask);
/**
* @brief Sets the priority of an interrupt.
*
* @param[in] id The interrupt ID. Must be <128.
* @param[in] prio The priority. 0 = highest, 14 = lowest, 15 = disabled
*/
void IRQ_setPriority(Interrupt id, u8 prio);
/**
* @brief Unregisters the interrupt service routine and disables the specified interrupt.
*
* @param[in] id The interrupt ID. Must be <128.
*/
void IRQ_unregisterIsr(Interrupt id);
#if !__thumb__
static inline u32 enterCriticalSection(void)
{
const u32 tmp = __getCpsr();
__cpsid(i);
return tmp & PSR_I;
}
static inline void leaveCriticalSection(u32 oldState)
{
__setCpsr_c((__getCpsr() & ~PSR_I) | oldState);
}
#endif

View File

@ -0,0 +1,133 @@
#pragma once
#include "types.h"
#include "mem_map.h"
#include "arm11/hardware/gx.h"
// LCD/ABL regs.
#define LCD_REGS_BASE (IO_MEM_ARM11_ONLY + 0x2000)
#define REG_LCD_PARALLAX_CNT *((vu32*)(LCD_REGS_BASE + 0x000)) // Controls PWM for the parallax barrier?
#define REG_LCD_PARALLAX_PWM *((vu32*)(LCD_REGS_BASE + 0x004)) // Frequency/other PWM stuff maybe?
#define REG_LCD_UNK00C *((vu32*)(LCD_REGS_BASE + 0x00C)) // Wtf is "FIX"?
#define REG_LCD_RST *((vu32*)(LCD_REGS_BASE + 0x014)) // Reset active low.
#define REG_LCD_ABL0_CNT *((vu32*)(LCD_REGS_BASE + 0x200)) // Bit 0 enables ABL aka power saving mode.
#define REG_LCD_ABL0_FILL *((vu32*)(LCD_REGS_BASE + 0x204))
#define REG_LCD_ABL0_LIGHT *((vu32*)(LCD_REGS_BASE + 0x240))
#define REG_LCD_ABL0_LIGHT_PWM *((vu32*)(LCD_REGS_BASE + 0x244))
#define REG_LCD_ABL1_CNT *((vu32*)(LCD_REGS_BASE + 0xA00)) // Bit 0 enables ABL aka power saving mode.
#define REG_LCD_ABL1_FILL *((vu32*)(LCD_REGS_BASE + 0xA04))
#define REG_LCD_ABL1_LIGHT *((vu32*)(LCD_REGS_BASE + 0xA40))
#define REG_LCD_ABL1_LIGHT_PWM *((vu32*)(LCD_REGS_BASE + 0xA44))
// Technically these regs belong in gx.h but they are used for LCD configuration so...
// Pitfall warning: The 3DS LCDs are physically rotated 90° CCW.
// PDC0 (top screen display controller) regs.
#define REG_LCD_PDC0_HTOTAL *((vu32*)(GX_REGS_BASE + 0x400))
#define REG_LCD_PDC0_VTOTAL *((vu32*)(GX_REGS_BASE + 0x424))
#define REG_LCD_PDC0_HPOS *((const vu32*)(GX_REGS_BASE + 0x450))
#define REG_LCD_PDC0_VPOS *((const vu32*)(GX_REGS_BASE + 0x454))
#define REG_LCD_PDC0_FB_A1 *((vu32*)(GX_REGS_BASE + 0x468))
#define REG_LCD_PDC0_FB_A2 *((vu32*)(GX_REGS_BASE + 0x46C))
#define REG_LCD_PDC0_FMT *((vu32*)(GX_REGS_BASE + 0x470))
#define REG_LCD_PDC0_CNT *((vu32*)(GX_REGS_BASE + 0x474))
#define REG_LCD_PDC0_SWAP *((vu32*)(GX_REGS_BASE + 0x478))
#define REG_LCD_PDC0_STAT *((const vu32*)(GX_REGS_BASE + 0x47C))
#define REG_LCD_PDC0_GTBL_IDX *((vu32*)(GX_REGS_BASE + 0x480)) // Gamma table index.
#define REG_LCD_PDC0_GTBL_FIFO *((vu32*)(GX_REGS_BASE + 0x484)) // Gamma table FIFO.
#define REG_LCD_PDC0_STRIDE *((vu32*)(GX_REGS_BASE + 0x490))
#define REG_LCD_PDC0_FB_B1 *((vu32*)(GX_REGS_BASE + 0x494))
#define REG_LCD_PDC0_FB_B2 *((vu32*)(GX_REGS_BASE + 0x498))
// PDC1 (bottom screen display controller) regs.
#define REG_LCD_PDC1_HTOTAL *((vu32*)(GX_REGS_BASE + 0x500))
#define REG_LCD_PDC1_VTOTAL *((vu32*)(GX_REGS_BASE + 0x524))
#define REG_LCD_PDC1_HPOS *((const vu32*)(GX_REGS_BASE + 0x550))
#define REG_LCD_PDC1_VPOS *((const vu32*)(GX_REGS_BASE + 0x554))
#define REG_LCD_PDC1_FB_A1 *((vu32*)(GX_REGS_BASE + 0x568))
#define REG_LCD_PDC1_FB_A2 *((vu32*)(GX_REGS_BASE + 0x56C))
#define REG_LCD_PDC1_FMT *((vu32*)(GX_REGS_BASE + 0x570))
#define REG_LCD_PDC1_CNT *((vu32*)(GX_REGS_BASE + 0x574))
#define REG_LCD_PDC1_SWAP *((vu32*)(GX_REGS_BASE + 0x578))
#define REG_LCD_PDC1_STAT *((const vu32*)(GX_REGS_BASE + 0x57C))
#define REG_LCD_PDC1_GTBL_IDX *((vu32*)(GX_REGS_BASE + 0x580)) // Gamma table index.
#define REG_LCD_PDC1_GTBL_FIFO *((vu32*)(GX_REGS_BASE + 0x584)) // Gamma table FIFO.
#define REG_LCD_PDC1_STRIDE *((vu32*)(GX_REGS_BASE + 0x590))
#define REG_LCD_PDC1_FB_B1 *((vu32*)(GX_REGS_BASE + 0x594))
#define REG_LCD_PDC1_FB_B2 *((vu32*)(GX_REGS_BASE + 0x598))
// REG_LCD_PDC_CNT
#define PDC_CNT_E (1u)
#define PDC_CNT_I_MASK_H (1u<<8) // Disables H(Blank?) IRQs.
#define PDC_CNT_I_MASK_V (1u<<9) // Disables VBlank IRQs.
#define PDC_CNT_I_MASK_ERR (1u<<10) // Disables error IRQs. What kind of errors?
#define PDC_CNT_I_MASK_ALL (PDC_CNT_I_MASK_ERR | PDC_CNT_I_MASK_V | PDC_CNT_I_MASK_H)
#define PDC_CNT_OUT_E (1u<<16) // Output enable?
// REG_LCD_PDC_SWAP
// Masks
#define PDC_SWAP_NEXT (1u) // Next framebuffer.
#define PDC_SWAP_CUR (1u<<4) // Currently displaying framebuffer?
// Bits
#define PDC_SWAP_RST_FIFO (1u<<8) // Which FIFO?
#define PDC_SWAP_I_H (1u<<16) // H(Blank?) IRQ bit.
#define PDC_SWAP_I_V (1u<<17) // VBlank IRQ bit.
#define PDC_SWAP_I_ERR (1u<<18) // Error IRQ bit?
#define PDC_SWAP_I_ALL (PDC_SWAP_I_ERR | PDC_SWAP_I_V | PDC_SWAP_I_H)
// LCD I2C regs.
typedef enum
{
LCD_I2C_REG_POWER = 0x01u,
LCD_I2C_REG_UNK11 = 0x11u,
LCD_I2C_REG_READ_ADDR = 0x40u,
LCD_I2C_REG_HS_SERIAL = 0x50u, // Highspeed serial for upper LCD only.
LCD_I2C_REG_UNK54 = 0x54u, // Checksum on/off?
LCD_I2C_REG_UNK55 = 0x55u, // Checksum status?
LCD_I2C_REG_STATUS = 0x60u, // Initially 0x01.
LCD_I2C_REG_BL_STATUS = 0x62u, // Backlight status.
LCD_I2C_REG_RST_STATUS = 0xFEu, // Reset status. Initially 0x00.
LCD_I2C_REG_REVISION = 0xFFu, // Revision/vendor infos.
} LcdI2cReg;
// LCD_I2C_REG_POWER
#define LCD_REG_POWER_BLACK (0x11u) // Force blackscreen.
#define LCD_REG_POWER_ON (0x10u) // Normal operation.
#define LCD_REG_POWER_OFF (0x00u) // LCD powered off.
// LCD_I2C_REG_UNK11
#define LCD_REG_UNK11_UNK10 (0x10u) // Written on init.
// LCD_I2C_REG_HS_SERIAL
#define LCD_REG_HS_SERIAL_ON (0x01u) // Enable highspeed serial.
// LCD_I2C_REG_UNK54
// LCD_I2C_REG_UNK55
// LCD_I2C_REG_STATUS
#define LCD_REG_STATUS_OK (0x00u)
#define LCD_REG_STATUS_ERR (0x01u)
// LCD_I2C_REG_BL_STATUS
#define LCD_REG_BL_STATUS_OFF (0x00u)
#define LCD_REG_BL_STATUS_ON (0x01u)
// LCD_I2C_REG_RST_STATUS
#define LCD_REG_RST_STATUS_NONE (0xAAu)
#define LCD_REG_RST_STATUS_RST (0x00u)
u8 LCDI2C_readReg(u8 lcd, LcdI2cReg reg);
void LCDI2C_writeReg(u8 lcd, LcdI2cReg reg, u8 data);
void LCDI2C_init(void);
void LCDI2C_waitBacklightsOn(void);
u16 LCDI2C_getRevisions(void);

View File

@ -0,0 +1,41 @@
#pragma once
#include "kevent.h"
// REG_LGYFB_CNT
#define LGYFB_ENABLE (1u)
#define LGYFB_VSCALE_E (1u<<1)
#define LGYFB_HSCALE_E (1u<<2)
#define LGYFB_SPATIAL_DITHER_E (1u<<4) // Unset behaves like weight 0xCCCC in both pattern regs.
#define LGYFB_TEMPORAL_DITHER_E (1u<<5) // Unset behaves like weight 0xCCCC in both pattern regs.
#define LGYFB_OUT_FMT_8888 (0u)
#define LGYFB_OUT_FMT_8880 (1u<<8)
#define LGYFB_OUT_FMT_5551 (2u<<8)
#define LGYFB_OUT_FMT_5650 (3u<<8)
#define LGYFB_ROT_NONE (0u)
#define LGYFB_ROT_90CW (1u<<10)
#define LGYFB_ROT_180CW (2u<<10)
#define LGYFB_ROT_270CW (3u<<10)
#define LGYFB_OUT_SWIZZLE (1u<<12)
#define LGYFB_DMA_E (1u<<15)
#define LGYFB_IN_FMT (1u<<16) // Use input format but this bit does nothing?
// REG_LGYFB_SIZE width and hight
#define LGYFB_SIZE(w, h) (((h) - 1)<<16 | ((w) - 1))
// REG_LGYFB_STAT and REG_LGYFB_IRQ
#define LGYFB_IRQ_DMA_REQ (1u)
#define LGYFB_IRQ_BUF_ERR (1u<<1) // FIFO overrun?
#define LGYFB_IRQ_VBLANK (1u<<2)
#define LGYFB_IRQ_MASK (LGYFB_IRQ_VBLANK | LGYFB_IRQ_BUF_ERR | LGYFB_IRQ_DMA_REQ)
#define LGYFB_OUT_LINE(reg) ((reg)>>16) // STAT only
void LGYFB_init(KEvent *frameReadyEvent);
void LGYFB_deinit(void);
#ifndef NDEBUG
void LGYFB_dbgDumpFrame(void);
#endif

View File

@ -0,0 +1,132 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#include "arm11/hardware/i2c.h"
typedef enum
{
MCU_REG_VERS_HIGH = 0x00u,
MCU_REG_VERS_LOW = 0x01u,
MCU_REG_3D_SLIDER = 0x08u,
MCU_REG_VOL_SLIDER = 0x09u, // 0-0x3F
MCU_REG_BATTERY = 0x0Bu,
MCU_REG_EX_HW_STATE = 0x0Fu,
MCU_REG_EVENTS = 0x10u,
MCU_REG_EVENT_MASK = 0x18u,
MCU_REG_POWER = 0x20u,
MCU_REG_LCDs = 0x22u,
MCU_REG_POWER_LED = 0x29u,
MCU_REG_WIFI_LED = 0x2Au,
MCU_REG_CAM_LED = 0x2Bu,
MCU_REG_3D_LED = 0x2Cu,
MCU_REG_RTC_TIME = 0x30u,
MCU_REG_RAW_STATE = 0x7Fu
} McuReg;
typedef enum
{
PWLED_AUTO = 0u,
//PWLED_BLUE = 1u, // wtf is "forced default blue"?
PWLED_SLEEP = 2u,
PWLED_OFF = 3u,
PWLED_RED = 4u,
PWLED_BLUE = 5u,
PWLED_BLINK_RED = 6u
} PwLedState;
u8 MCU_readReg(McuReg reg);
bool MCU_writeReg(McuReg reg, u8 data);
bool MCU_readRegBuf(McuReg reg, u8 *out, u32 size);
bool MCU_writeRegBuf(McuReg reg, const u8 *const in, u32 size);
void MCU_init(void);
bool MCU_setEventMask(u32 mask);
u32 MCU_getEvents(u32 mask);
u32 MCU_waitEvents(u32 mask);
static inline u8 MCU_getBatteryLevel(void)
{
u8 state;
if(!MCU_readRegBuf(MCU_REG_BATTERY, &state, 1)) return 0;
return state;
}
static inline u8 MCU_getExternalHwState(void)
{
return MCU_readReg(MCU_REG_EX_HW_STATE);
}
static inline void MCU_powerOffSys(void)
{
I2C_writeRegIntSafe(I2C_DEV_CTR_MCU, MCU_REG_POWER, 1u);
}
static inline void MCU_rebootSys(void)
{
I2C_writeRegIntSafe(I2C_DEV_CTR_MCU, MCU_REG_POWER, 1u<<2);
}
static inline void MCU_controlLCDPower(u8 bits)
{
MCU_writeReg(MCU_REG_LCDs, bits);
}
static inline bool MCU_setPowerLedState(PwLedState state)
{
return MCU_writeReg(MCU_REG_POWER_LED, state);
}
static inline bool MCU_getRTCTime(u8 rtc[7])
{
if(!rtc) return true;
return MCU_readRegBuf(MCU_REG_RTC_TIME, rtc, 7);
}
static inline u8 MCU_getSystemModel(void)
{
u8 buf[10];
if(!MCU_readRegBuf(MCU_REG_RAW_STATE, buf, sizeof(buf))) return 0xFF;
return buf[9];
}
static inline u8 MCU_getHidHeld(void)
{
u8 data[19];
if(!MCU_readRegBuf(MCU_REG_RAW_STATE, data, sizeof(data))) return 0xFF;
return data[18];
}

View File

@ -0,0 +1,136 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2020 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#include "mem_map.h"
#define PDN_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x41000)
#define REG_PDN_CNT *((vu16*)(PDN_REGS_BASE + 0x000))
#define REG_PDN_WAKE_ENABLE *((vu32*)(PDN_REGS_BASE + 0x008))
#define REG_PDN_WAKE_REASON *((vu32*)(PDN_REGS_BASE + 0x00C)) // Write 1 to acknowledge and 0 to clear?
#define REG_PDN_GPU_CNT *((vu32*)(PDN_REGS_BASE + 0x200))
#define REG_PDN_VRAM_CNT *((vu8* )(PDN_REGS_BASE + 0x204)) // This reg doesn't seem to exist on retail hardware.
#define REG_PDN_LCD_CNT *((vu8* )(PDN_REGS_BASE + 0x208)) // This reg doesn't seem to exist on retail hardware.
#define REG_PDN_FCRAM_CNT *((vu8* )(PDN_REGS_BASE + 0x210))
#define REG_PDN_I2S_CNT *((vu8* )(PDN_REGS_BASE + 0x220))
#define REG_PDN_CAM_CNT *((vu8* )(PDN_REGS_BASE + 0x224))
#define REG_PDN_DSP_CNT *((vu8* )(PDN_REGS_BASE + 0x230))
#define REG_PDN_G1_CNT *((vu8* )(PDN_REGS_BASE + 0x240)) // Hantro G1 decoder.
#define REG_PDN_MPCORE_SOCMODE *((vu16*)(PDN_REGS_BASE + 0x300))
#define REG_PDN_MPCORE_CNT *((vu16*)(PDN_REGS_BASE + 0x304)) // Is this reg actually only vu8?
#define REGs_PDN_MPCORE_BOOTCNT ((vu8* )(PDN_REGS_BASE + 0x310))
// REG_PDN_CNT
#define PDN_CNT_SLEEP (1u) // Set this bit to enter sleep mode.
#define PDN_CNT_VRAM_OFF (1u<<15) // Set when VRAM is powered off.
// REG_PDN_WAKE_ENABLE and REG_PDN_WAKE_REASON
enum
{
PDN_WAKE_PADCNT = 1u,
PDN_WAKE_SHELL_OPENED = 1u<<3,
PDN_WAKE_HEADPH_NOT_PLUGGED_IN = 1u<<4, // Really?
PDN_WAKE_UNK6 = 1u<<6, // DSi mode related.
PDN_WAKE_SDIO1 = 1u<<7,
PDN_WAKE_SDIO2 = 1u<<8,
PDN_WAKE_SDIO3 = 1u<<16,
// 17-28 maybe GPIO3 0-11?
PDN_WAKE_GAMECARD_INSERT = 1u<<29, // ?
PDN_WAKE_TOUCHPEN_DOWN = 1u<<30,
PDN_WAKE_UNK31 = 1u<<31 // Also shell related?
};
// REG_PDN_GPU_CNT
// Note: The resets are active low.
enum
{
PDN_GPU_CNT_RST_REGS = 1u, // And more?
PDN_GPU_CNT_RST_PSC = 1u<<1, // ?
PDN_GPU_CNT_RST_GEOSHADER = 1u<<2, // ?
PDN_GPU_CNT_RST_RASTERIZER = 1u<<3, // ?
PDN_GPU_CNT_RST_PPF = 1u<<4,
PDN_GPU_CNT_RST_PDC = 1u<<5, // ?
PDN_GPU_CNT_RST_PDC2 = 1u<<6, // Maybe pixel pipeline or so?
PDN_GPU_CNT_RST_ALL = (PDN_GPU_CNT_RST_PDC2<<1) - 1
};
#define PDN_GPU_CNT_CLK_E (1u<<16)
// REG_PDN_VRAM_CNT
#define PDN_VRAM_CNT_CLK_E (1u)
// REG_PDN_LCD_CNT
#define PDN_LCD_CNT_PWR_MGR_OFF (1u) // Power management off?
// REG_PDN_FCRAM_CNT
// Note: Reset is active low.
#define PDN_FCRAM_CNT_RST (1u)
#define PDN_FCRAM_CNT_CLK_E (1u<<1)
#define PDN_FCRAM_CNT_CLK_E_ACK (1u<<2) // Gets set or unset depending on CLK_E.
// REG_PDN_I2S_CNT
#define PDN_I2S_CNT_I2S_CLK1_E (1u) // ? Unused?
#define PDN_I2S_CNT_I2S_CLK2_E (1u<<1)
// REG_PDN_CAM_CNT
#define PDN_CAM_CNT_CLK_E (1u)
// REG_PDN_DSP_CNT
// Note: Reset is active low.
#define PDN_DSP_CNT_RST (1u)
#define PDN_DSP_CNT_CLK_E (1u<<1)
// REG_PDN_G1_CNT
// TODO: Active low or high?
#define PDN_G1_CNT_RST (1u)
// REG_PDN_MPCORE_SOCMODE
typedef enum
{
SOCMODE_O3DS_268MHz = 0u,
SOCMODE_N3DS_268MHz = 1u, // Also enables FCRAM extension.
SOCMODE_N3DS_PROTO_268MHz = 2u, // Also enables FCRAM extension?
SOCMODE_N3DS_PROTO_536MHz = 3u, // Also enables FCRAM extension?
SOCMODE_N3DS_804MHz = 5u, // Also enables FCRAM extension.
SOCMODE_MASK = 7u
} PdnSocmode;
#define PDN_MPCORE_SOCMODE_ACK (1u<<15)
// REG_PDN_MPCORE_CNT
#define PDN_MPCORE_CNT_MEM_EXT_E (1u) // Does it actually affect all mem extensions or just QTM?
#define PDN_MPCORE_CNT_L2C_E (1u<<8)
// REGs_PDN_MPCORE_BOOTCNT
// Note: Reset is active low.
#define MPCORE_BOOTCNT_RST (1u) // Core 2/3 only. Reset and instruction overlay enable.
#define MPCORE_BOOTCNT_D_OVERL_E (1u<<1) // Core 2/3 only. Data overlay enable. Also used to signal a core booted.
#define MPCORE_BOOTCNT_RST_STAT (1u<<4)
#define MPCORE_BOOTCNT_UNK (1u<<5)
void PDN_core123Init(void);
void PDN_setSocmode(PdnSocmode socmode);
void PDN_poweroffCore23(void);

View File

@ -0,0 +1,71 @@
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Refer to http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0360f/index.html
// (comprocessor regs c15) for documentation.
#include "types.h"
static inline void startProfiling(u16 pmnEvents, u8 intMask, bool ccntDiv64, u8 reset)
{
const u32 tmp = pmnEvents<<12 | 7u<<8 | intMask<<4 | ccntDiv64<<3 | reset<<1 | 1u;
__asm__ volatile("mcr p15, 0, %0, c15, c12, 0" : : "r" (tmp) : "memory");
}
static inline void stopProfiling(void)
{
__asm__ volatile("mcr p15, 0, %0, c15, c12, 0" : : "r" (7u<<8) : "memory");
}
static inline void setCcnt(u32 val)
{
__asm__ volatile("mcr p15, 0, %0, c15, c12, 1" : : "r" (val) : "memory");
}
static inline void setPmn0(u32 val)
{
__asm__ volatile("mcr p15, 0, %0, c15, c12, 2" : : "r" (val) : "memory");
}
static inline void setPmn1(u32 val)
{
__asm__ volatile("mcr p15, 0, %0, c15, c12, 3" : : "r" (val) : "memory");
}
static inline u32 getCcnt(void)
{
u32 tmp;
__asm__ volatile("mrc p15, 0, %0, c15, c12, 1" : "=r" (tmp) : : "memory");
return tmp;
}
static inline u32 getPmn0(void)
{
u32 tmp;
__asm__ volatile("mrc p15, 0, %0, c15, c12, 2" : "=r" (tmp) : : "memory");
return tmp;
}
static inline u32 getPmn1(void)
{
u32 tmp;
__asm__ volatile("mrc p15, 0, %0, c15, c12, 3" : "=r" (tmp) : : "memory");
return tmp;
}

View File

@ -0,0 +1,29 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#include "mem_map.h"
#define SCU_REGS_BASE (MPCORE_PRIV_REG_BASE)
#define REG_SCU_CNT *((vu32*)(SCU_REGS_BASE + 0x00))
#define REG_SCU_CONFIG *((vu32*)(SCU_REGS_BASE + 0x04))
#define REG_SCU_CPU_STAT *((vu32*)(SCU_REGS_BASE + 0x08))
#define REG_SCU_INVAL_TAG *((vu32*)(SCU_REGS_BASE + 0x0C))

View File

@ -0,0 +1,120 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2019 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
// REG_NSPI_CNT
#define NSPI_BUS_1BIT (0u)
#define NSPI_BUS_4BIT (1u<<12)
#define NSPI_DIR_READ (0u)
#define NSPI_DIR_WRITE (1u<<13)
#define NSPI_ENABLE (1u<<15)
// REG_NSPI_CS
#define NSPI_DESELECT (0u)
// NSPI_FIFO_STAT
#define NSPI_FIFO_BUSY (1u)
// REG_NSPI_AUTOPOLL
#define NSPI_AUTOPOLL_START (1u<<31)
// REG_NSPI_INT_MASK Bit set = disabled.
// REG_NSPI_INT_STAT Status and aknowledge.
#define NSPI_INT_TRANSF_END (1u) // Also fires on each auto poll try.
#define NSPI_INT_AP_SUCCESS (1u<<1) // Auto poll
#define NSPI_INT_AP_TIMEOUT (1u<<2) // Auto poll
// Old interface clocks.
enum
{
SPI_CLK_4MHz = 0u,
SPI_CLK_2MHz = 1u,
SPI_CLK_1MHz = 2u,
SPI_CLK_512KHz = 3u,
SPI_CLK_8MHz = 4u // Only in DSi/3DS mode.
};
// New interface clocks.
enum
{
NSPI_CLK_512KHz = 0u,
NSPI_CLK_1MHz = 1u,
NSPI_CLK_2MHz = 2u,
NSPI_CLK_4MHz = 3u,
NSPI_CLK_8MHz = 4u,
NSPI_CLK_16MHz = 5u
};
typedef enum
{
NSPI_DEV_POWERMAN = 0u, // Unused DS(i) mode power management
NSPI_DEV_NVRAM = 1u, // WiFi SPI flash
NSPI_DEV_TWL_CODEC = 2u,
NSPI_DEV_CTR_CODEC = 3u,
NSPI_DEV_UNUSED5 = 4u, // Unused "CS2".
NSPI_DEV_UNUSED6 = 5u, // Unused "CS3".
NSPI_DEV_UNUSED7 = 6u // Debugger?
} SpiDevice;
/**
* @brief Initializes the SPI buses. Call this only once.
*/
void NSPI_init(void);
/**
* @brief Automatically polls a bit of the command response. Use with the macro below.
*
* @param[in] dev The device ID. See table above.
* @param[in] params The parameters. Use the macro below.
*
* @return Returns false on failure/timeout and true on success.
*/
bool _NSPI_autoPollBit(SpiDevice dev, u32 params);
/**
* @brief Writes and/or reads data to/from a SPI device.
*
* @param[in] dev The device ID. See table above.
* @param[in] in Input data pointer for write.
* @param out Output data pointer for read.
* @param[in] inSize Input size. Must be <= 0x1FFFFF.
* @param[in] outSize Output size. Must be <= 0x1FFFFF.
* @param[in] done Set to true if this is the last transfer (chip select).
*/
void NSPI_writeRead(SpiDevice dev, const u32 *in, u32 *out, u32 inSize, u32 outSize, bool done);
/**
* @brief Automatically polls a bit of the command response.
*
* @param[in] dev The device ID. See table above.
* @param[in] cmd The command.
* @param[in] timeout The timeout. Must be 0-15. Tries = 31<<NspiClk + timeout.
* @param[in] off The bit offset. Must be 0-7.
* @param[in] bitSet Poll for a set ur unset bit.
*
* @return Returns false on failure/timeout and true on success.
*/
#define NSPI_autoPollBit(dev, cmd, timeout, off, bitSet) _NSPI_autoPollBit(dev, (bitSet)<<30 | (off)<<24 | (timeout)<<16 | (cmd))

View File

@ -0,0 +1,31 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2019 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#define SPIFLASH_CMD_RDSR (0x05)
#define SPIFLASH_CMD_READ (0x03)
// true if spiflash is installed, false otherwise
bool spiflash_get_status(void);
void spiflash_read(u32 offset, u32 size, u32 *buf);

View File

@ -0,0 +1,79 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#define TIMER_BASE_FREQ (268111856.f)
#define TIMER_ENABLE (1u)
#define TIMER_SINGLE_SHOT (0u)
#define TIMER_AUTO_RELOAD (1u<<1)
#define TIMER_IRQ_ENABLE (1u<<2)
// p is the prescaler value and n the frequence
#define TIMER_FREQ(p, f) (TIMER_BASE_FREQ / 2 / (p) / (f))
/**
* @brief Resets/initializes the timer hardware. Should not be called manually.
*/
void TIMER_init(void);
/**
* @brief Starts the timer.
*
* @param[in] prescaler The prescaler value.
* @param[in] ticks The initial number of ticks. This is also the
* reload value in auto reload mode.
* @param[in] autoReload Set to true for auto reload. false for single shot.
* @param[in] enableIrq Timer fires IRQs on underflow if true.
*/
void TIMER_start(u8 prescaler, u32 ticks, bool autoReload, bool enableIrq);
/**
* @brief Returns the current number of ticks of the timer.
*
* @return The number of ticks.
*/
u32 TIMER_getTicks(void);
/**
* @brief Stops the timer and returns the current number of ticks.
*
* @return The number of ticks.
*/
u32 TIMER_stop(void);
/**
* @brief Halts the CPU for the specified number of ticks.
* Use the function below for a milliseconds version.
*
* @param[in] ticks The number of ticks to sleep.
*/
void TIMER_sleepTicks(u32 ticks);
// Sleeps ms milliseconds. ms can be up to 32000.
static inline void TIMER_sleepMs(u32 ms)
{
TIMER_sleepTicks(TIMER_FREQ(1, 1000) * ms);
}

View File

@ -1,38 +1,9 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "error_codes.h"
#ifdef __cplusplus
extern "C"
{
#endif
Result oafParseConfigEarly(void);
void changeBacklight(s16 amount);
Result oafInitAndRun(void);
void oafUpdate(void);
void oafFinish(void);
#ifdef __cplusplus
} // extern "C"
#endif

24
include/arm11/power.h Normal file
View File

@ -0,0 +1,24 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
noreturn void power_off(void);
noreturn void power_reboot(void);

45
include/arm11/spinlock.h Normal file
View File

@ -0,0 +1,45 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
static inline void spinlockLock(u32 *lock)
{
u32 tmp;
__asm__ volatile("1: ldrex %0, [%1]\n"
" teq %0, #0\n"
" wfene\n"
" strexeq %0, %2, [%1]\n"
" teqeq %0, #0\n"
" bne 1b\n"
" mcr p15, 0, %0, c7, c10, 5" // DMB
: "=&r" (tmp) : "r" (lock), "r" (1) : "cc", "memory");
}
static inline void spinlockUnlock(u32 *lock)
{
__asm__ volatile("mcr p15, 0, %0, c7, c10, 5\n" // DMB
"str %0, [%1]\n"
"mcr p15, 0, %0, c7, c10, 4\n" // DSB
"sev"
: : "r" (0), "r" (lock) : "memory");
}

View File

@ -1,6 +1,8 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2024 profi200
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -17,9 +19,8 @@
*/
#include "types.h"
#include "kernel.h"
KHandle OAF_videoInit(void);
void OAF_videoExit(void);
noreturn void _start(void);
void deinitCpu(void);

149
include/arm11/util/rbtree.h Normal file
View File

@ -0,0 +1,149 @@
/**
* @file rbtree.h
* @brief Red-black trees.
*/
#pragma once
#include <stdint.h>
#include <stddef.h>
/// Retrieves an rbtree item.
#define rbtree_item(ptr, type, member) \
((type*)(((char*)ptr) - offsetof(type, member)))
typedef struct rbtree rbtree_t; ///< rbtree type.
typedef struct rbtree_node rbtree_node_t; ///< rbtree node type.
typedef void (*rbtree_node_destructor_t)(rbtree_node_t *Node); ///< rbtree node destructor.
typedef int (*rbtree_node_comparator_t)(const rbtree_node_t *lhs,
const rbtree_node_t *rhs); ///< rbtree node comparator.
/// An rbtree node.
struct rbtree_node
{
uintptr_t parent_color; ///< Parent color.
rbtree_node_t *child[2]; ///< Node children.
};
/// An rbtree.
struct rbtree
{
rbtree_node_t *root; ///< Root node.
rbtree_node_comparator_t comparator; ///< Node comparator.
size_t size; ///< Size.
};
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initializes an rbtree.
* @param tree Pointer to the tree.
* @param comparator Comparator to use.
*/
void
rbtree_init(rbtree_t *tree,
rbtree_node_comparator_t comparator);
/**
* @brief Gets whether an rbtree is empty
* @param tree Pointer to the tree.
* @return A non-zero value if the tree is not empty.
*/
int
rbtree_empty(const rbtree_t *tree);
/**
* @brief Gets the size of an rbtree.
* @param tree Pointer to the tree.
*/
size_t
rbtree_size(const rbtree_t *tree);
/**
* @brief Inserts a node into an rbtree.
* @param tree Pointer to the tree.
* @param node Pointer to the node.
* @return The inserted node.
*/
__attribute__((warn_unused_result))
rbtree_node_t*
rbtree_insert(rbtree_t *tree,
rbtree_node_t *node);
/**
* @brief Inserts multiple nodes into an rbtree.
* @param tree Pointer to the tree.
* @param node Pointer to the nodes.
*/
void
rbtree_insert_multi(rbtree_t *tree,
rbtree_node_t *node);
/**
* @brief Finds a node within an rbtree.
* @param tree Pointer to the tree.
* @param node Pointer to the node.
* @return The located node.
*/
rbtree_node_t*
rbtree_find(const rbtree_t *tree,
const rbtree_node_t *node);
/**
* @brief Gets the minimum node of an rbtree.
* @param tree Pointer to the tree.
* @return The minimum node.
*/
rbtree_node_t*
rbtree_min(const rbtree_t *tree);
/**
* @brief Gets the maximum node of an rbtree.
* @param tree Pointer to the tree.
* @return The maximum node.
*/
rbtree_node_t*
rbtree_max(const rbtree_t *tree);
/**
* @brief Gets the next node from an rbtree node.
* @param node Pointer to the node.
* @return The next node.
*/
rbtree_node_t*
rbtree_node_next(const rbtree_node_t *node);
/**
* @brief Gets the previous node from an rbtree node.
* @param node Pointer to the node.
* @return The previous node.
*/
rbtree_node_t*
rbtree_node_prev(const rbtree_node_t *node);
/**
* @brief Removes a node from an rbtree.
* @param tree Pointer to the tree.
* @param node Pointer to the node.
* @param destructor Destructor to use when removing the node.
* @return The removed node.
*/
rbtree_node_t*
rbtree_remove(rbtree_t *tree,
rbtree_node_t *node,
rbtree_node_destructor_t destructor);
/**
* @brief Clears an rbtree.
* @param tree Pointer to the tree.
* @param destructor Destructor to use when clearing the tree's nodes.
*/
void
rbtree_clear(rbtree_t *tree,
rbtree_node_destructor_t destructor);
#ifdef __cplusplus
}
#endif

12
include/arm9/arm7_stub.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include "types.h"
noreturn void _a7_overlay_stub(void);
extern const u32 _a7_overlay_stub_size[];
noreturn void _a7_stub_start(void);
extern u16 _a7_stub9_swi[]; // Final ARM9 mem location.
extern const u32 _a7_stub_size[];

View File

@ -1,8 +1,8 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2024 profi200
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -22,13 +22,6 @@
#ifdef __cplusplus
extern "C"
{
#endif
void makeOpenBusPaddingFast(u32 *romEnd);
#ifdef __cplusplus
} // extern "C"
#endif
noreturn void panic();
noreturn void panicMsg(const char *msg);
//void dumpMem(u8 *mem, u32 size, char *filepath);

View File

@ -0,0 +1,29 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2018 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "mem_map.h"
#define CFG9_REGS_BASE (IO_MEM_ARM9_ONLY)
#define REG_CFG9_SYSPROT9 *((vu8* )(CFG9_REGS_BASE + 0x00000))
#define REG_CFG9_SYSPROT11 *((vu8* )(CFG9_REGS_BASE + 0x00001))
#define REG_CFG9_SOCINFO *((vu16*)(CFG9_REGS_BASE + 0x00FFC))
#define REG_CFG9_BOOTENV *((vu32*)(CFG9_REGS_BASE + 0x10000))
#define REG_CFG9_UNITINFO *((vu8* )(CFG9_REGS_BASE + 0x10010))

View File

@ -0,0 +1,338 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
//////////////////////////////////
// AES //
//////////////////////////////////
#define AES_MAX_BLOCKS (0xFFFE) // Aligned for 32 bytes transfers
#define AES_WRITE_FIFO_COUNT (REG_AESCNT & 0x1F)
#define AES_READ_FIFO_COUNT (REG_AESCNT & 0x3E0)
#define AES_FLUSH_READ_FIFO (1u<<10)
#define AES_FLUSH_WRITE_FIFO (1u<<11)
#define AES_MAC_SIZE(n) ((((n) - 2) / 2)<<16)
#define AES_PASS_PAYLOARD (1u<<19) // Passes the associated data to REG_AESRDFIFO
#define AES_MAC_SRC_REG (1u<<20)
#define AES_IS_MAC_VALID ((bool)(REG_AESCNT>>21 & 1u))
#define AES_OUTPUT_BIG (1u)
#define AES_OUTPUT_LITTLE (0u)
#define AES_INPUT_BIG (1u)
#define AES_INPUT_LITTLE (0u)
#define AES_OUTPUT_NORMAL (4u)
#define AES_OUTPUT_REVERSED (0u)
#define AES_INPUT_NORMAL (4u)
#define AES_INPUT_REVERSED (0u)
#define AES_UPDATE_KEYSLOT (1u<<26)
#define AES_IRQ_ENABLE (1u<<30)
#define AES_ENABLE (1u<<31)
#define AES_MODE_CCM_DECRYPT (0u)
#define AES_MODE_CCM_ENCRYPT (1u<<27)
#define AES_MODE_CTR (2u<<27)
#define AES_MODE_CBC_DECRYPT (4u<<27)
#define AES_MODE_CBC_ENCRYPT (5u<<27)
#define AES_MODE_ECB_DECRYPT (6u<<27)
#define AES_MODE_ECB_ENCRYPT (7u<<27)
typedef enum
{
AES_KEY_NORMAL = 0u,
AES_KEY_X = 1u,
AES_KEY_Y = 2u
} AesKeyType;
typedef struct
{
u32 ctrIvNonceParams;
u32 ctrIvNonce[4];
u32 aesParams;
} AES_ctx;
/**
* @brief Initializes the AES hardware and the NDMA channels used by it.
*/
void AES_init(void);
/**
* @brief Deinits AES to workaround a K9L bug.
*/
void AES_deinit(void);
/**
* @brief Sets a AES key in the specified keyslot.
*
* @param[in] keyslot The keyslot this key will be set for.
* @param[in] type The key type. Can be AES_KEY_NORMAL/X/Y.
* @param[in] orderEndianess Word order and endianess bitmask.
* @param[in] twlScrambler Set to true to use the TWL keyscrambler for keyslots > 0x03.
* @param[in] key Pointer to 128-bit AES key data.
*/
void AES_setKey(u8 keyslot, AesKeyType type, u8 orderEndianess, bool twlScrambler, const u32 key[4]);
/**
* @brief Selects the given keyslot for all following crypto operations.
*
* @param[in] keyslot The keyslot to select.
*/
void AES_selectKeyslot(u8 keyslot);
/**
* @brief Copies the given nonce into internal state.
*
* @param ctx Pointer to AES_ctx (AES context).
* @param[in] orderEndianess Word order and endianess bitmask.
* @param[in] nonce Pointer to the nonce data.
*/
void AES_setNonce(AES_ctx *const ctx, u8 orderEndianess, const u32 nonce[3]);
/**
* @brief Copies the given counter/initialization vector into internal state.
*
* @param ctx Pointer to AES_ctx (AES context).
* @param[in] orderEndianess Word order and endianess bitmask.
* @param[in] ctrIv Pointer to the counter/initialization vector data.
*/
void AES_setCtrIv(AES_ctx *const ctx, u8 orderEndianess, const u32 ctrIv[4]);
/**
* @brief Increments the internal counter with the given value (CTR mode).
*
* @param ctr Pointer to the counter data.
* @param[in] val Value to increment the counter with.
*/
void AES_addCounter(u32 ctr[4], u32 val);
/**
* @brief Sets params in the AES context for all following crypto operations.
*
* @param ctx Pointer to AES_ctx (AES context).
* @param[in] inEndianessOrder Input endianess and word order bitmask.
* @param[in] outEndianessOrder Output endianess and word order bitmask.
*/
void AES_setCryptParams(AES_ctx *const ctx, u8 inEndianessOrder, u8 outEndianessOrder);
/**
* @brief En-/decrypts data with AES CTR.
*
* @param ctx Pointer to AES_ctx (AES context).
* @param[in] in In data pointer. Can be the same as out.
* @param out Out data pointer. Can be the same as in.
* @param[in] blocks Number of blocks to process. 1 block is 16 bytes.
* @param[in] dma Set to true to enable DMA.
*/
void AES_ctr(AES_ctx *const ctx, const u32 *in, u32 *out, u32 blocks, bool dma);
/**
* @brief En-/decrypts data with AES CBC.
* @brief Note: With DMA the output buffer must be invalidated
* @brief after this function, not before.
*
* @param ctx Pointer to AES_ctx (AES context).
* @param[in] in In data pointer. Can be the same as out.
* @param out Out data pointer. Can be the same as in.
* @param[in] blocks Number of blocks to process. 1 block is 16 bytes.
* @param[in] enc Set to true to encrypt and false to decrypt.
* @param[in] dma Set to true to enable DMA.
*/
//void AES_cbc(AES_ctx *const ctx, const u32 *in, u32 *out, u32 blocks, bool enc, bool dma);
/**
* @brief En-/decrypts data with AES ECB.
*
* @param ctx Pointer to AES_ctx (AES context).
* @param[in] in In data pointer. Can be the same as out.
* @param out Out data pointer. Can be the same as in.
* @param[in] blocks Number of blocks to process. 1 block is 16 bytes.
* @param[in] enc Set to true to encrypt and false to decrypt.
* @param[in] dma Set to true to enable DMA.
*/
void AES_ecb(AES_ctx *const ctx, const u32 *in, u32 *out, u32 blocks, bool enc, bool dma);
/**
* @brief En-/decrypts data with AES CCM.
* @brief Note: The AES hardware implements this in a non-standard way
* @brief limiting it to 1 nonce for 1 MB.
*
* @param ctx Pointer to AES_ctx (AES context).
* @param[in] in In data pointer. Can be the same as out.
* @param out Out data pointer. Can be the same as in.
* @param[in] macSize The AES MAC size in bytes.
* @param mac Pointer to in/out AES MAC. The MAC must/will be padded
* with zeros (non-standard).
* @param[in] blocks Number of blocks to process. 1 block is 16 bytes.
* @param[in] enc Set to true to encrypt and false to decrypt.
*
* @return Returns true in decryption mode if the AES MAC is valid. Otherwise true.
*/
bool AES_ccm(const AES_ctx *const ctx, const u32 *const in, u32 *const out, u32 macSize,
u32 mac[4], u16 blocks, bool enc);
//////////////////////////////////
// SHA //
//////////////////////////////////
#define SHA_ENABLE (1u) // Also used as busy flag
#define SHA_FINAL_ROUND (1u<<1)
#define SHA_IN_DMA_ENABLE (1u<<2) // Without this NDMA startup is never fires
#define SHA_INPUT_BIG (1u<<3)
#define SHA_INPUT_LITTLE (0u)
#define SHA_OUTPUT_BIG (SHA_INPUT_BIG)
#define SHA_OUTPUT_LITTLE (SHA_INPUT_LITTLE)
#define SHA_MODE_256 (0u)
#define SHA_MODE_224 (1u<<4)
#define SHA_MODE_1 (2u<<4)
#define SHA_MODE_MASK (SHA_MODE_1 | SHA_MODE_224 | SHA_MODE_256)
/**
* @brief Sets input mode, endianess and starts the hash operation.
*
* @param[in] params Mode and input endianess bitmask.
*/
void SHA_start(u8 params);
/**
* @brief Hashes the data pointed to.
*
* @param[in] data Pointer to data to hash.
* @param[in] size Size of the data to hash.
*/
void SHA_update(const u32 *data, u32 size);
/**
* @brief Generates the final hash.
*
* @param hash Pointer to memory to copy the hash to.
* @param[in] endianess Endianess bitmask for the hash.
*/
void SHA_finish(u32 *const hash, u8 endianess);
/**
* @brief Returns the current SHA engine state.
*
* @param out Pointer to memory to copy the state to.
*/
void SHA_getState(u32 *const out);
/**
* @brief Hashes a single block of data and outputs the hash.
*
* @param[in] data Pointer to data to hash.
* @param[in] size Size of the data to hash.
* @param hash Pointer to memory to copy the hash to.
* @param[in] params Mode and input endianess bitmask.
* @param[in] hashEndianess Endianess bitmask for the hash.
*/
void sha(const u32 *data, u32 size, u32 *const hash, u8 params, u8 hashEndianess);
/**
* @brief Hashes a single block of data with DMA and outputs the hash.
* @brief Note: Not recommended. It's way slower than CPU based SHA.
*
* @param[in] data Pointer to data to hash.
* @param[in] size Size of the data to hash. Must be 64 bytes aligned.
* @param hash Pointer to memory to copy the hash to.
* @param[in] params Mode and input endianess bitmask.
* @param[in] hashEndianess Endianess bitmask for the hash.
*/
//void sha_dma(const u32 *data, u32 size, u32 *const hash, u8 params, u8 hashEndianess);
//////////////////////////////////
// RSA //
//////////////////////////////////
// REG_RSA_CNT
#define RSA_CNT_ENABLE (1u)
#define RSA_CNT_IRQ_ENABLE (1u<<1)
#define RSA_CNT_KEYSLOT_SHIFT (4u)
#define RSA_CNT_KEYSLOT_MASK (3u<<RSA_CNT_KEYSLOT_SHIFT)
#define RSA_CNT_INPUT_BIG (1u<<8)
#define RSA_CNT_INPUT_LITTLE (0u)
#define RSA_CNT_INPUT_NORMAL (1u<<9)
#define RSA_CNT_INPUT_REVERSED (0u)
#define RSA_CNT_INPUT_MASK (RSA_CNT_INPUT_NORMAL | RSA_CNT_INPUT_BIG)
// REG_RSA_SLOTCNT
#define RSA_SLOTCNT_SET (1u)
#define RSA_SLOTCNT_WR_PROT (1u<<1)
#define RSA_SLOTCNT_BIT31 (1u<<31)
// REG_RSA_SLOTSIZE
#define RSA_SLOTSIZE_2048 (0x40u)
/**
* @brief Initializes the RSA hardware.
*/
void RSA_init(void);
/**
* @brief Selects the given keyslot for all following RSA operations.
*
* @param[in] keyslot The keyslot to select.
*/
void RSA_selectKeyslot(u8 keyslot);
/**
* @brief Sets a RSA modulus + exponent in the specified keyslot.
*
* @param[in] keyslot The keyslot this key will be set for.
* @param[in] mod Pointer to 2048-bit RSA modulus data.
* @param[in] exp The exponent to set.
*
* @return Returns true on success, false otherwise.
*/
bool RSA_setKey2048(u8 keyslot, const u32 *const mod, u32 exp);
/**
* @brief Decrypts a RSA 2048 signature.
*
* @param decSig Pointer to decrypted destination signature.
* @param[in] encSig Pointer to encrypted source signature.
*
* @return Returns true on success, false otherwise.
*/
bool RSA_decrypt2048(u32 *const decSig, const u32 *const encSig);
/**
* @brief Verifies a RSA 2048 SHA 256 signature.
* @brief Note: This function skips the ASN.1 data and is therefore not safe.
*
* @param[in] encSig Pointer to encrypted source signature.
* @param[in] data Pointer to the data to hash.
* @param[in] size The hash data size.
*
* @return Returns true if the signature is valid, false otherwise.
*/
bool RSA_verify2048(const u32 *const encSig, const u32 *const data, u32 size);

View File

@ -0,0 +1,34 @@
#pragma once
/*
* This code is part of ctrulib (https://github.com/smealum/ctrulib)
*/
#include "types.h"
#define HID_KEY_MASK_ALL ((KEY_Y << 1) - 1)
#define HID_VERBOSE_MODE_BUTTONS (KEY_SELECT | KEY_START)
enum
{
KEY_A = 1u,
KEY_B = 1u<<1,
KEY_SELECT = 1u<<2,
KEY_START = 1u<<3,
KEY_DRIGHT = 1u<<4,
KEY_DLEFT = 1u<<5,
KEY_DUP = 1u<<6,
KEY_DDOWN = 1u<<7,
KEY_R = 1u<<8,
KEY_L = 1u<<9,
KEY_X = 1u<<10,
KEY_Y = 1u<<11
};
void hidScanInput(void);
u32 hidKeysHeld(void);
u32 hidKeysDown(void);
u32 hidKeysUp(void);

View File

@ -0,0 +1,99 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "arm.h"
#include "types.h"
typedef enum
{
IRQ_DMAC_1_0 = 0u, // DMAC_1 = NDMA
IRQ_DMAC_1_1 = 1u,
IRQ_DMAC_1_2 = 2u,
IRQ_DMAC_1_3 = 3u,
IRQ_DMAC_1_4 = 4u,
IRQ_DMAC_1_5 = 5u,
IRQ_DMAC_1_6 = 6u,
IRQ_DMAC_1_7 = 7u,
IRQ_TIMER_0 = 8u,
IRQ_TIMER_1 = 9u,
IRQ_TIMER_2 = 10u,
IRQ_TIMER_3 = 11u,
IRQ_PXI_SYNC = 12u,
IRQ_PXI_NOT_FULL = 13u,
IRQ_PXI_NOT_EMPTY = 14u,
IRQ_AES = 15u,
IRQ_SDIO_1 = 16u,
IRQ_SDIO_1_ASYNC = 17u,
IRQ_SDIO_3 = 18u,
IRQ_SDIO_3_ASYNC = 19u,
IRQ_DEBUG_RECV = 20u,
IRQ_DEBUG_SEND = 21u,
IRQ_RSA = 22u,
IRQ_CTR_CARD_1 = 23u, // SPICARD and CTRCARD too?
IRQ_CTR_CARD_2 = 24u,
IRQ_CGC = 25u,
IRQ_CGC_DET = 26u,
IRQ_DS_CARD = 27u,
IRQ_DMAC_2 = 28u,
IRQ_DMAC_2_ABORT = 29u
} Interrupt;
// IRQ interrupt service routine type.
// id: contains the interrupt ID
typedef void (*IrqIsr)(u32 id);
/**
* @brief Initializes interrupts.
*/
void IRQ_init(void);
/**
* @brief Registers a interrupt service routine and enables the specified interrupt.
*
* @param[in] id The interrupt ID. Must be <32.
* @param[in] isr The interrupt service routine to call.
*/
void IRQ_registerIsr(Interrupt id, IrqIsr isr);
/**
* @brief Unregisters the interrupt service routine and disables the specified interrupt.
*
* @param[in] id The interrupt ID. Must be <32.
*/
void IRQ_unregisterIsr(Interrupt id);
#if !__thumb__
static inline u32 enterCriticalSection(void)
{
u32 tmp;
__setCpsr_c((tmp = __getCpsr()) | PSR_I);
return tmp & PSR_I;
}
static inline void leaveCriticalSection(u32 oldState)
{
__setCpsr_c((__getCpsr() & ~PSR_I) | oldState);
}
#endif

View File

@ -0,0 +1,189 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "mem_map.h"
#include "types.h"
#include "util.h"
#define NDMA_REGS_BASE (IO_MEM_ARM9_ONLY + 0x2000)
#define REG_NDMA_GLOBAL_CNT *((vu32*)(NDMA_REGS_BASE + 0x00))
#define REG_NDMA0_SRC_ADDR *((vu32*)(NDMA_REGS_BASE + 0x04))
#define REG_NDMA0_DST_ADDR *((vu32*)(NDMA_REGS_BASE + 0x08))
#define REG_NDMA0_TOTAL_CNT *((vu32*)(NDMA_REGS_BASE + 0x0C)) // Total repeat length in words
#define REG_NDMA0_LOG_BLK_CNT *((vu32*)(NDMA_REGS_BASE + 0x10)) // Logical block size in words
#define REG_NDMA0_INT_CNT *((vu32*)(NDMA_REGS_BASE + 0x14)) // Timing/interval settings
#define REG_NDMA0_FILL_DATA *((vu32*)(NDMA_REGS_BASE + 0x18))
#define REG_NDMA0_CNT *((vu32*)(NDMA_REGS_BASE + 0x1C))
#define REG_NDMA1_SRC_ADDR *((vu32*)(NDMA_REGS_BASE + 0x20))
#define REG_NDMA1_DST_ADDR *((vu32*)(NDMA_REGS_BASE + 0x24))
#define REG_NDMA1_TOTAL_CNT *((vu32*)(NDMA_REGS_BASE + 0x28))
#define REG_NDMA1_LOG_BLK_CNT *((vu32*)(NDMA_REGS_BASE + 0x2C))
#define REG_NDMA1_INT_CNT *((vu32*)(NDMA_REGS_BASE + 0x30))
#define REG_NDMA1_FILL_DATA *((vu32*)(NDMA_REGS_BASE + 0x34))
#define REG_NDMA1_CNT *((vu32*)(NDMA_REGS_BASE + 0x38))
#define REG_NDMA2_SRC_ADDR *((vu32*)(NDMA_REGS_BASE + 0x3C))
#define REG_NDMA2_DST_ADDR *((vu32*)(NDMA_REGS_BASE + 0x40))
#define REG_NDMA2_TOTAL_CNT *((vu32*)(NDMA_REGS_BASE + 0x44))
#define REG_NDMA2_LOG_BLK_CNT *((vu32*)(NDMA_REGS_BASE + 0x48))
#define REG_NDMA2_INT_CNT *((vu32*)(NDMA_REGS_BASE + 0x4C))
#define REG_NDMA2_FILL_DATA *((vu32*)(NDMA_REGS_BASE + 0x50))
#define REG_NDMA2_CNT *((vu32*)(NDMA_REGS_BASE + 0x54))
#define REG_NDMA3_SRC_ADDR *((vu32*)(NDMA_REGS_BASE + 0x58))
#define REG_NDMA3_DST_ADDR *((vu32*)(NDMA_REGS_BASE + 0x5C))
#define REG_NDMA3_TOTAL_CNT *((vu32*)(NDMA_REGS_BASE + 0x60))
#define REG_NDMA3_LOG_BLK_CNT *((vu32*)(NDMA_REGS_BASE + 0x64))
#define REG_NDMA3_INT_CNT *((vu32*)(NDMA_REGS_BASE + 0x68))
#define REG_NDMA3_FILL_DATA *((vu32*)(NDMA_REGS_BASE + 0x6C))
#define REG_NDMA3_CNT *((vu32*)(NDMA_REGS_BASE + 0x70))
#define REG_NDMA4_SRC_ADDR *((vu32*)(NDMA_REGS_BASE + 0x74))
#define REG_NDMA4_DST_ADDR *((vu32*)(NDMA_REGS_BASE + 0x78))
#define REG_NDMA4_TOTAL_CNT *((vu32*)(NDMA_REGS_BASE + 0x7C))
#define REG_NDMA4_LOG_BLK_CNT *((vu32*)(NDMA_REGS_BASE + 0x80))
#define REG_NDMA4_INT_CNT *((vu32*)(NDMA_REGS_BASE + 0x84))
#define REG_NDMA4_FILL_DATA *((vu32*)(NDMA_REGS_BASE + 0x88))
#define REG_NDMA4_CNT *((vu32*)(NDMA_REGS_BASE + 0x8C))
#define REG_NDMA5_SRC_ADDR *((vu32*)(NDMA_REGS_BASE + 0x90))
#define REG_NDMA5_DST_ADDR *((vu32*)(NDMA_REGS_BASE + 0x94))
#define REG_NDMA5_TOTAL_CNT *((vu32*)(NDMA_REGS_BASE + 0x98))
#define REG_NDMA5_LOG_BLK_CNT *((vu32*)(NDMA_REGS_BASE + 0x9C))
#define REG_NDMA5_INT_CNT *((vu32*)(NDMA_REGS_BASE + 0xA0))
#define REG_NDMA5_FILL_DATA *((vu32*)(NDMA_REGS_BASE + 0xA4))
#define REG_NDMA5_CNT *((vu32*)(NDMA_REGS_BASE + 0xA8))
#define REG_NDMA6_SRC_ADDR *((vu32*)(NDMA_REGS_BASE + 0xAC))
#define REG_NDMA6_DST_ADDR *((vu32*)(NDMA_REGS_BASE + 0xB0))
#define REG_NDMA6_TOTAL_CNT *((vu32*)(NDMA_REGS_BASE + 0xB4))
#define REG_NDMA6_LOG_BLK_CNT *((vu32*)(NDMA_REGS_BASE + 0xB8))
#define REG_NDMA6_INT_CNT *((vu32*)(NDMA_REGS_BASE + 0xBC))
#define REG_NDMA6_FILL_DATA *((vu32*)(NDMA_REGS_BASE + 0xC0))
#define REG_NDMA6_CNT *((vu32*)(NDMA_REGS_BASE + 0xC4))
#define REG_NDMA7_SRC_ADDR *((vu32*)(NDMA_REGS_BASE + 0xC8))
#define REG_NDMA7_DST_ADDR *((vu32*)(NDMA_REGS_BASE + 0xCC))
#define REG_NDMA7_TOTAL_CNT *((vu32*)(NDMA_REGS_BASE + 0xD0))
#define REG_NDMA7_LOG_BLK_CNT *((vu32*)(NDMA_REGS_BASE + 0xD4))
#define REG_NDMA7_INT_CNT *((vu32*)(NDMA_REGS_BASE + 0xD8))
#define REG_NDMA7_FILL_DATA *((vu32*)(NDMA_REGS_BASE + 0xDC))
#define REG_NDMA7_CNT *((vu32*)(NDMA_REGS_BASE + 0xE0))
#define REG_NDMA_SRC_ADDR(n) *((vu32*)(NDMA_REGS_BASE + 0x04 + ((n) * 28)))
#define REG_NDMA_DST_ADDR(n) *((vu32*)(NDMA_REGS_BASE + 0x08 + ((n) * 28)))
#define REG_NDMA_TOTAL_CNT(n) *((vu32*)(NDMA_REGS_BASE + 0x0C + ((n) * 28)))
#define REG_NDMA_LOG_BLK_CNT(n) *((vu32*)(NDMA_REGS_BASE + 0x10 + ((n) * 28)))
#define REG_NDMA_INT_CNT(n) *((vu32*)(NDMA_REGS_BASE + 0x14 + ((n) * 28)))
#define REG_NDMA_FILL_DATA(n) *((vu32*)(NDMA_REGS_BASE + 0x18 + ((n) * 28)))
#define REG_NDMA_CNT(n) *((vu32*)(NDMA_REGS_BASE + 0x1C + ((n) * 28)))
// REG_NDMA_GLOBAL_CNT
#define NDMA_ROUND_ROBIN(n) (intLog2(n)<<16 | 1u<<31 | 1u) // n = number of CPU cycles
#define NDMA_HIGHEST_PRIO (1u)
// REG_NDMA_INT_CNT
#define NDMA_INT_SYS_FREQ (0u)
// REG_NDMA_CNT
#define NDMA_DST_UPDATE_INC (0u)
#define NDMA_DST_UPDATE_DEC (1u<<10)
#define NDMA_DST_UPDATE_FIXED (2u<<10)
#define NDMA_DST_ADDR_RELOAD (1u<<12) // Reloads on logical block end
#define NDMA_SRC_UPDATE_INC (0u)
#define NDMA_SRC_UPDATE_DEC (1u<<13)
#define NDMA_SRC_UPDATE_FIXED (2u<<13)
#define NDMA_SRC_UPDATE_FILL (3u<<13)
#define NDMA_SRC_ADDR_RELOAD (1u<<15)
// The block length is 2^n words (Example: 2^15 = 32768 words = 0x20000 bytes)
#define NDMA_BURST_WORDS(n) (intLog2(n)<<16)
#define NDMA_IMMEDIATE_MODE (16u<<24)
#define NDMA_TOTAL_CNT_MODE (0u)
#define NDMA_REPEATING_MODE (1u<<29)
#define NDMA_IRQ_ENABLE (1u<<30)
#define NDMA_ENABLE (1u<<31)
enum
{
NDMA_STARTUP_TIMER0 = 0u<<24,
NDMA_STARTUP_TIMER1 = 1u<<24,
NDMA_STARTUP_TIMER2 = 2u<<24,
NDMA_STARTUP_TIMER3 = 3u<<24,
NDMA_STARTUP_CTRCARD0 = 4u<<24, // Fires with SPICARD aswell but seems to be broken.
NDMA_STARTUP_CTRCARD1 = 5u<<24, // Fires with SPICARD aswell but seems to be broken.
NDMA_STARTUP_MMC1 = 6u<<24,
NDMA_STARTUP_MMC2 = 7u<<24, // Guess based on DSi documentation
NDMA_STARTUP_AES_IN = 8u<<24, // AES write fifo
NDMA_STARTUP_AES_OUT = 9u<<24, // AES read fifo
NDMA_STARTUP_SHA_IN = 10u<<24,
NDMA_STARTUP_SHA_OUT = 11u<<24, // For chaining
NDMA_STARTUP_UNK_12 = 12u<<24,
NDMA_STARTUP_UNK_13 = 13u<<24,
NDMA_STARTUP_UNK_14 = 14u<<24,
NDMA_STARTUP_MMC_AES_SHA = 15u<<24 // Unconfirmed
};
/**
* @brief Initializes all NDMA channels.
*/
void NDMA_init(void);
/**
* @brief Asynchronous copying of data using the NDMA engine.
*
* @param dest Pointer to destination memory. Must be 4 bytes aligned.
* @param source Pointer to source data. Must be 4 bytes aligned.
* @param[in] size The size of the data. Must be multiple of 4.
*/
void NDMA_copyAsync(u32 *dest, const u32 *source, u32 num);
/**
* @brief Copies data using the NDMA engine.
*
* @param dest Pointer to destination memory. Must be 4 bytes aligned.
* @param source Pointer to source data. Must be 4 bytes aligned.
* @param[in] size The size of the data. Must be multiple of 4.
*/
void NDMA_copy(u32 *dest, const u32 *source, u32 size);
/**
* @brief Asynchronous memory fill with the given value using the NDMA engine.
*
* @param dest Pointer to destination memory. Must be 4 bytes aligned.
* @param[in] value The value each 32-bit word will be set to.
* @param[in] size The size of the memory to fill. Must be multiple of 4.
*/
void NDMA_fillAsync(u32 *dest, u32 value, u32 size);
/**
* @brief Fills memory with the given value using the NDMA engine.
*
* @param dest Pointer to destination memory. Must be 4 bytes aligned.
* @param[in] value The value each 32-bit word will be set to.
* @param[in] size The size of the memory to fill. Must be multiple of 4.
*/
void NDMA_fill(u32 *dest, u32 value, u32 size);

View File

@ -0,0 +1,183 @@
#ifndef __SDMMC_H__
#define __SDMMC_H__
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright (c) 2014-2015, Normmatt
*
* Alternatively, the contents of this file may be used under the terms
* of the GNU General Public License Version 2, as described below:
*
* This file is free software: you may copy, redistribute and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
#include <stdint.h>
#include "types.h"
#define SDMMC_BASE (0x10006000)
#define REG_SDCMD (0x00)
#define REG_SDPORTSEL (0x02)
#define REG_SDCMDARG (0x04)
#define REG_SDCMDARG0 (0x04)
#define REG_SDCMDARG1 (0x06)
#define REG_SDSTOP (0x08)
#define REG_SDBLKCOUNT (0x0a)
#define REG_SDRESP0 (0x0c)
#define REG_SDRESP1 (0x0e)
#define REG_SDRESP2 (0x10)
#define REG_SDRESP3 (0x12)
#define REG_SDRESP4 (0x14)
#define REG_SDRESP5 (0x16)
#define REG_SDRESP6 (0x18)
#define REG_SDRESP7 (0x1a)
#define REG_SDSTATUS0 (0x1c)
#define REG_SDSTATUS1 (0x1e)
#define REG_SDIRMASK0 (0x20)
#define REG_SDIRMASK1 (0x22)
#define REG_SDCLKCTL (0x24)
#define REG_SDBLKLEN (0x26)
#define REG_SDOPT (0x28)
#define REG_SDFIFO (0x30)
#define REG_DATACTL (0xd8)
#define REG_SDRESET (0xe0)
#define REG_SDPROTECTED (0xf6) //bit 0 determines if sd is protected or not?
#define REG_DATACTL32 (0x100)
#define REG_SDBLKLEN32 (0x104)
#define REG_SDBLKCOUNT32 (0x108)
#define REG_SDFIFO32 (0x10C)
#define REG_CLK_AND_WAIT_CTL (0x138)
#define REG_RESET_SDIO (0x1e0)
#define TMIO_STAT0_CMDRESPEND (0x0001)
#define TMIO_STAT0_DATAEND (0x0004)
#define TMIO_STAT0_CARD_REMOVE (0x0008)
#define TMIO_STAT0_CARD_INSERT (0x0010)
#define TMIO_STAT0_SIGSTATE (0x0020)
#define TMIO_STAT0_WRPROTECT (0x0080)
#define TMIO_STAT0_CARD_REMOVE_A (0x0100)
#define TMIO_STAT0_CARD_INSERT_A (0x0200)
#define TMIO_STAT0_SIGSTATE_A (0x0400)
#define TMIO_STAT1_CMD_IDX_ERR (0x0001)
#define TMIO_STAT1_CRCFAIL (0x0002)
#define TMIO_STAT1_STOPBIT_ERR (0x0004)
#define TMIO_STAT1_DATATIMEOUT (0x0008)
#define TMIO_STAT1_RXOVERFLOW (0x0010)
#define TMIO_STAT1_TXUNDERRUN (0x0020)
#define TMIO_STAT1_CMDTIMEOUT (0x0040)
#define TMIO_STAT1_RXRDY (0x0100)
#define TMIO_STAT1_TXRQ (0x0200)
#define TMIO_STAT1_ILL_FUNC (0x2000)
#define TMIO_STAT1_CMD_BUSY (0x4000)
#define TMIO_STAT1_ILL_ACCESS (0x8000)
#define TMIO_MASK_ALL (0x837F031D)
#define TMIO_MASK_GW (TMIO_STAT1_ILL_ACCESS | TMIO_STAT1_CMDTIMEOUT | TMIO_STAT1_TXUNDERRUN | TMIO_STAT1_RXOVERFLOW | \
TMIO_STAT1_DATATIMEOUT | TMIO_STAT1_STOPBIT_ERR | TMIO_STAT1_CRCFAIL | TMIO_STAT1_CMD_IDX_ERR)
#define TMIO_MASK_READOP (TMIO_STAT1_RXRDY | TMIO_STAT1_DATAEND)
#define TMIO_MASK_WRITEOP (TMIO_STAT1_TXRQ | TMIO_STAT1_DATAEND)
#ifdef __cplusplus
extern "C" {
#endif
typedef struct mmcdevice {
u8* rData;
const u8* tData;
u32 size;
u32 error;
u16 stat0;
u16 stat1;
u32 ret[4];
u32 initarg;
u32 isSDHC;
u32 clk;
u32 SDOPT;
u32 devicenumber;
u32 total_size; //size in sectors of the device
u32 res;
} mmcdevice;
void sdmmc_init();
int sdmmc_sdcard_readsector(u32 sector_no, u8 *out);
int sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, u8 *out);
int sdmmc_sdcard_writesector(u32 sector_no, const u8 *in);
int sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, const u8 *in);
int sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, u8 *out);
int sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, const u8 *in);
int sdmmc_get_cid(bool isNand, u32 *info);
mmcdevice *getMMCDevice(int drive);
int Nand_Init();
int SD_Init();
#ifdef __cplusplus
};
#endif
//---------------------------------------------------------------------------------
static inline u16 sdmmc_read16(u16 reg) {
//---------------------------------------------------------------------------------
return *(volatile u16*)(SDMMC_BASE + reg);
}
//---------------------------------------------------------------------------------
static inline void sdmmc_write16(u16 reg, u16 val) {
//---------------------------------------------------------------------------------
*(volatile u16*)(SDMMC_BASE + reg) = val;
}
//---------------------------------------------------------------------------------
static inline u32 sdmmc_read32(u16 reg) {
//---------------------------------------------------------------------------------
return *(volatile u32*)(SDMMC_BASE + reg);
}
//---------------------------------------------------------------------------------
static inline void sdmmc_write32(u16 reg, u32 val) {
//---------------------------------------------------------------------------------
*(volatile u32*)(SDMMC_BASE + reg) = val;
}
//---------------------------------------------------------------------------------
static inline void sdmmc_mask16(u16 reg, const u16 clear, const u16 set) {
//---------------------------------------------------------------------------------
u16 val = sdmmc_read16(reg);
val &= ~clear;
val |= set;
sdmmc_write16(reg, val);
}
static inline void setckl(u32 data)
{
sdmmc_write16(REG_SDCLKCTL, data & 0xFF);
sdmmc_write16(REG_SDCLKCTL, 1u<<8 | (data & 0x2FF));
}
#endif

View File

@ -0,0 +1,96 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2019 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
// REG_NSPI_CNT
#define NSPI_BUS_1BIT (0u)
#define NSPI_BUS_4BIT (1u<<12)
#define NSPI_DIR_READ (0u)
#define NSPI_DIR_WRITE (1u<<13)
#define NSPI_ENABLE (1u<<15)
// REG_NSPI_CS
#define NSPI_DESELECT (0u)
// NSPI_FIFO_STAT
#define NSPI_FIFO_BUSY (1u)
// REG_NSPI_AUTOPOLL
#define NSPI_AUTOPOLL_START (1u<<31)
// REG_NSPI_INT_MASK Bit set = disabled.
// REG_NSPI_INT_STAT Status and aknowledge.
#define NSPI_INT_TRANSF_END (1u) // Also fires on each auto poll try.
#define NSPI_INT_AP_SUCCESS (1u<<1) // Auto poll
#define NSPI_INT_AP_TIMEOUT (1u<<2) // Auto poll
typedef enum
{
NSPI_CLK_512KHz = 0u,
NSPI_CLK_1MHz = 1u,
NSPI_CLK_2MHz = 2u,
NSPI_CLK_4MHz = 3u,
NSPI_CLK_8MHz = 4u,
NSPI_CLK_16MHz = 5u
} NspiClk;
/**
* @brief Initializes the SPI buses. Call this only once.
*/
void SPICARD_init(void);
/**
* @brief Automatically polls a bit of the command response. Use with the macro below.
*
* @param[in] params The parameters. Use the macro below.
*
* @return Returns false on failure/timeout and true on success.
*/
bool _SPICARD_autoPollBit(u32 params);
/**
* @brief Writes and/or reads data to/from a SPI device.
*
* @param[in] clk The clock frequency to use.
* @param[in] in Input data pointer for write.
* @param out Output data pointer for read.
* @param[in] inSize Input size. Must be <= 0x1FFFFF.
* @param[in] outSize Output size. Must be <= 0x1FFFFF.
* @param[in] done Set to true if this is the last transfer (chip select).
*/
void SPICARD_writeRead(NspiClk clk, const u32 *in, u32 *out, u32 inSize, u32 outSize, bool done);
/**
* @brief Automatically polls a bit of the command response.
*
* @param[in] cmd The command.
* @param[in] timeout The timeout. Must be 0-15. Tries = 31<<NspiClk + timeout.
* @param[in] off The bit offset. Must be 0-7.
* @param[in] bitSet Poll for a set ur unset bit.
*
* @return Returns false on failure/timeout and true on success.
*/
#define SPICARD_autoPollBit(cmd, timeout, off, bitSet) _SPICARD_autoPollBit((bitSet)<<30 | (off)<<24 | (timeout)<<16 | (cmd))

View File

@ -0,0 +1,94 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#define TIMER_BASE_FREQ (67027964)
#define TIMER_COUNT_UP (1u<<2) // For cascading at least 2 timers
#define TIMER_IRQ_ENABLE (1u<<6)
#define TIMER_ENABLE (1u<<7)
// Convenience macros for calculating the ticks. Based on libnds
#define TIMER_FREQ(n) (-TIMER_BASE_FREQ / (n))
#define TIMER_FREQ_64(n) (-(TIMER_BASE_FREQ / 64) / (n))
#define TIMER_FREQ_256(n) (-(TIMER_BASE_FREQ / 256) / (n))
#define TIMER_FREQ_1024(n) (-(TIMER_BASE_FREQ / 1024) / (n))
typedef enum
{
TIMER_0 = 0u,
TIMER_1 = 1u,
TIMER_2 = 2u,
TIMER_3 = 3u
} Timer;
typedef enum
{
TIMER_PRESCALER_1 = 0u,
TIMER_PRESCALER_64 = 1u,
TIMER_PRESCALER_256 = 2u,
TIMER_PRESCALER_1024 = 3u
} TimerPrescaler;
/**
* @brief Resets/initializes the timer hardware. Should not be called manually.
*/
void TIMER_init(void);
/**
* @brief Starts a timer.
*
* @param[in] timer The timer to start.
* @param[in] prescaler The prescaler to use.
* @param[in] ticks The initial number of ticks. This is also the reload
* value on overflow.
* @param[in] enableIrq Timer fires IRQs if true.
*/
void TIMER_start(Timer timer, TimerPrescaler prescaler, u16 ticks, bool enableIrq);
/**
* @brief Returns the current number of ticks of the timer.
*
* @param[in] timer The timer get the ticks from.
*
* @return The number of ticks.
*/
u16 TIMER_getTicks(Timer timer);
/**
* @brief Stops a timer and returns the current number of ticks.
*
* @param[in] timer The timer to stop.
*
* @return The number of ticks.
*/
u16 TIMER_stop(Timer timer);
/**
* @brief Halts the CPU for the specified number of milliseconds.
*
* @param[in] ms The number of milliseconds to sleep.
*/
void TIMER_sleep(u32 ms);

View File

@ -1,8 +1,8 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2022 spitzeqc
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -18,15 +18,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#ifdef __cplusplus
extern "C"
{
#endif
Result patchRom(const char *const gamePath, u32 *romSize);
#ifdef __cplusplus
} // extern "C"
#endif
void deinitCpu(void);

265
include/arm_intrinsic.h Normal file
View File

@ -0,0 +1,265 @@
#pragma once
// Based on: https://github.com/ARM-software/CMSIS_5/blob/master/CMSIS/Core/Include/cmsis_gcc.h
#include "types.h"
// u32 result, u32 op1.
#define MAKE_INTR_U32_1OP(isVolatile, inst) \
ALWAYS_INLINE u32 __##inst(u32 op1) \
{ \
u32 res; \
if(isVolatile == 1) \
__asm__ volatile(#inst " %0, %1" : "=r" (res) : "r" (op1) : ); \
else \
__asm__(#inst " %0, %1" : "=r" (res) : "r" (op1) : ); \
return res; \
}
// u32 result, u32 op1, u32 op2.
#define MAKE_INTR_U32_2OPS(isVolatile, inst) \
ALWAYS_INLINE u32 __##inst(u32 op1, u32 op2) \
{ \
u32 res; \
if(isVolatile == 1) \
__asm__ volatile(#inst " %0, %1, %2" : "=r" (res) : "r" (op1), "r" (op2) : ); \
else \
__asm__(#inst " %0, %1, %2" : "=r" (res) : "r" (op1), "r" (op2) : ); \
return res; \
}
// s32 result, s32 op1, s32 op2.
#define MAKE_INTR_S32_2OPS(isVolatile, inst) \
ALWAYS_INLINE s32 __##inst(s32 op1, s32 op2) \
{ \
s32 res; \
if(isVolatile == 1) \
__asm__ volatile(#inst " %0, %1, %2" : "=r" (res) : "r" (op1), "r" (op2) : ); \
else \
__asm__(#inst " %0, %1, %2" : "=r" (res) : "r" (op1), "r" (op2) : ); \
return res; \
}
// u32 result, u32 op1, u32 op2, u32 op3.
#define MAKE_INTR_U32_3OPS(isVolatile, inst) \
ALWAYS_INLINE u32 __##inst(u32 op1, u32 op2, u32 op3) \
{ \
u32 res; \
if(isVolatile == 1) \
__asm__ volatile(#inst " %0, %1, %2, %3" : "=r" (res) : "r" (op1), "r" (op2), "r" (op3) : ); \
else \
__asm__(#inst " %0, %1, %2, %3" : "=r" (res) : "r" (op1), "r" (op2), "r" (op3) : ); \
return res; \
}
// s32 result, s32 op1, s32 op2, s32 op3.
#define MAKE_INTR_S32_3OPS(isVolatile, inst) \
ALWAYS_INLINE s32 __##inst(s32 op1, s32 op2, s32 op3) \
{ \
s32 res; \
if(isVolatile == 1) \
__asm__ volatile(#inst " %0, %1, %2, %3" : "=r" (res) : "r" (op1), "r" (op2), "r" (op3) : ); \
else \
__asm__(#inst " %0, %1, %2, %3" : "=r" (res) : "r" (op1), "r" (op2), "r" (op3) : ); \
return res; \
}
#ifndef __ARMEB__ // Little endian
// Special instruction with shared u64 input and output.
// u64 result, u32 op1, u32 op2, u64 acc.
#define MAKE_INTR_U64_U32_U32_U64(isVolatile, inst) \
ALWAYS_INLINE u64 __##inst(u32 op1, u32 op2, u64 acc) \
{ \
union \
{ \
u32 r32[2]; \
u64 r64; \
} r; \
r.r64 = acc; \
\
if(isVolatile == 1) \
__asm__ volatile(#inst " %0, %1, %2, %3" : "=r" (r.r32[0]), "=r" (r.r32[1]) : "r" (op1), "r" (op2), "0" (r.r32[0]), "1" (r.r32[1]) : ); \
else \
__asm__(#inst " %0, %1, %2, %3" : "=r" (r.r32[0]), "=r" (r.r32[1]) : "r" (op1), "r" (op2), "0" (r.r32[0]), "1" (r.r32[1]) : ); \
\
return r.r64; \
}
#else // Big endian
// Special instruction with shared u64 input and output.
// u64 result, u32 op1, u32 op2, u64 acc.
#define MAKE_INTR_U64_U32_U32_U64(isVolatile, inst) \
ALWAYS_INLINE u64 __##inst(u32 op1, u32 op2, u64 acc) \
{ \
union \
{ \
u32 r32[2]; \
u64 r64; \
} r; \
r.r64 = acc; \
\
if(isVolatile == 1) \
__asm__ volatile(#inst " %0, %1, %2, %3" : "=r" (r.r32[1]), "=r" (r.r32[0]) : "r" (op1), "r" (op2), "0" (r.r32[1]), "1" (r.r32[0]) : ); \
else \
__asm__(#inst " %0, %1, %2, %3" : "=r" (r.r32[1]), "=r" (r.r32[0]) : "r" (op1), "r" (op2), "0" (r.r32[1]), "1" (r.r32[0]) : ); \
\
return r.r64; \
}
#endif // #ifndef __ARMEB__
// Pack Halfword Bottom Top.
#define __pkhbt(op1, op2, sh) \
({ \
u32 __res; \
__asm__("pkhbt %0, %1, %2, lsl %3" : "=r" (__res) : "r" (op1), "r" (op2), "I" (sh) : ); \
__res; \
})
// Pack Halfword Top Bottom.
#define __pkhtb(op1, op2, sh) \
({ \
u32 __res, __sh = (sh); \
if(__sh == 0) \
__asm__("pkhtb %0, %1, %2" : "=r" (__res) : "r" (op1), "r" (op2) : ); \
else \
__asm__("pkhtb %0, %1, %2, asr %3" : "=r" (__res) : "r" (op1), "r" (op2), "I" (__sh) : ); \
__res; \
})
MAKE_INTR_S32_2OPS(1, qadd) // Signed saturating addition.
MAKE_INTR_U32_2OPS(0, qadd8) // Signed saturating parallel byte-wise addition.
MAKE_INTR_U32_2OPS(0, qadd16) // Signed saturating parallel halfword-wise addition.
MAKE_INTR_U32_2OPS(0, qasx) // Signed saturating parallel add and subtract halfwords with exchange.
MAKE_INTR_S32_2OPS(1, qdadd) // Signed saturating Double and Add.
MAKE_INTR_S32_2OPS(1, qdsub) // Signed saturating Double and Subtract.
MAKE_INTR_U32_2OPS(0, qsax) // Signed saturating parallel subtract and add halfwords with exchange.
MAKE_INTR_S32_2OPS(1, qsub) // Signed saturating Subtract.
MAKE_INTR_U32_2OPS(0, qsub8) // Signed saturating parallel byte-wise subtraction.
MAKE_INTR_U32_2OPS(0, qsub16) // Signed saturating parallel halfword-wise subtraction.
MAKE_INTR_U32_1OP(0, rev) // Reverse the byte order in a word.
MAKE_INTR_U32_1OP(0, rev16) // Reverse the byte order in each halfword independently.
MAKE_INTR_U32_1OP(0, revsh) // Reverse the byte order in the bottom halfword, and sign extend to 32 bits.
MAKE_INTR_U32_2OPS(1, sadd8) // Signed parallel byte-wise addition.
MAKE_INTR_U32_2OPS(1, sadd16) // Signed parallel halfword-wise addition.
MAKE_INTR_U32_2OPS(1, sasx) // Signed parallel add and subtract halfwords with exchange.
MAKE_INTR_U32_2OPS(1, sel) // Select bytes from each operand according to the state of the APSR GE flags.
MAKE_INTR_U32_2OPS(0, shadd8) // Signed halving parallel byte-wise addition.
MAKE_INTR_U32_2OPS(0, shadd16) // Signed halving parallel halfword-wise addition.
MAKE_INTR_U32_2OPS(0, shasx) // Signed halving parallel add and subtract halfwords with exchange.
MAKE_INTR_U32_2OPS(0, shsax) // Signed halving parallel subtract and add halfwords with exchange.
MAKE_INTR_U32_2OPS(0, shsub8) // Signed halving parallel byte-wise subtraction.
MAKE_INTR_U32_2OPS(0, shsub16) // Signed halving parallel halfword-wise subtraction.
MAKE_INTR_U32_3OPS(1, smlabb) // Signed Multiply Accumulate, with 16-bit operands (bottom, bottom) and a 32-bit result and accumulator.
MAKE_INTR_U32_3OPS(1, smlabt) // Signed Multiply Accumulate, with 16-bit operands (bottom, top) and a 32-bit result and accumulator.
MAKE_INTR_U32_3OPS(1, smlatb) // Signed Multiply Accumulate, with 16-bit operands (top, bottom) and a 32-bit result and accumulator.
MAKE_INTR_U32_3OPS(1, smlatt) // Signed Multiply Accumulate, with 16-bit operands (top, top) and a 32-bit result and accumulator.
MAKE_INTR_U32_3OPS(0, smlad) // Dual 16-bit Signed Multiply with Addition of products and 32-bit accumulation.
MAKE_INTR_U32_3OPS(0, smladx) // Dual 16-bit Signed exchange Multiply with Addition of products and 32-bit accumulation.
MAKE_INTR_U64_U32_U32_U64(0, smlal) // Signed Long Multiply, with optional Accumulate, with 32-bit operands, and 64-bit result and accumulator.
MAKE_INTR_U64_U32_U32_U64(0, smlald) // Dual 16-bit Signed Multiply with Addition of products and 64-bit Accumulation.
MAKE_INTR_U64_U32_U32_U64(0, smlaldx) // Dual 16-bit Signed exchange Multiply with Addition of products and 64-bit Accumulation.
MAKE_INTR_U64_U32_U32_U64(0, smlalbb) // Signed Multiply-Accumulate with 16-bit operands (bottom, bottom) and a 64-bit accumulator.
MAKE_INTR_U64_U32_U32_U64(0, smlalbt) // Signed Multiply-Accumulate with 16-bit operands (bottom, top) and a 64-bit accumulator.
MAKE_INTR_U64_U32_U32_U64(0, smlaltb) // Signed Multiply-Accumulate with 16-bit operands (top, bottom) and a 64-bit accumulator.
MAKE_INTR_U64_U32_U32_U64(0, smlaltt) // Signed Multiply-Accumulate with 16-bit operands (top, top) and a 64-bit accumulator.
MAKE_INTR_U32_3OPS(1, smlawb) // Signed Multiply-Accumulate Wide, with one 32-bit operand and one 16-bit operand (bottom half), and a 32-bit accumulate value, providing the top 32 bits of the result.
MAKE_INTR_U32_3OPS(1, smlawt) // Signed Multiply-Accumulate Wide, with one 32-bit operand and one 16-bit operand (top half), and a 32-bit accumulate value, providing the top 32 bits of the result.
MAKE_INTR_U32_3OPS(0, smlsd) // Dual 16-bit Signed Multiply with Subtraction of products and 32-bit accumulation.
MAKE_INTR_U32_3OPS(0, smlsdx) // Dual 16-bit Signed exchange Multiply with Subtraction of products and 32-bit accumulation.
MAKE_INTR_U64_U32_U32_U64(0, smlsld) // Dual 16-bit Signed Multiply with Subtraction of products and 64-bit Accumulation.
MAKE_INTR_U64_U32_U32_U64(0, smlsldx) // Dual 16-bit Signed exchange Multiply with Subtraction of products and 64-bit Accumulation.
MAKE_INTR_S32_3OPS(0, smmla) // Signed Most significant word Multiply with Accumulation.
MAKE_INTR_S32_3OPS(0, smmlar) // Signed Most significant word Multiply with Accumulation and rounding.
MAKE_INTR_S32_3OPS(0, smmls) // Signed Most significant word Multiply with Subtraction.
MAKE_INTR_S32_2OPS(0, smmlsr) // Signed Most significant word Multiply with Subtraction and rounding.
MAKE_INTR_S32_2OPS(0, smmul) // Signed Most significant word Multiply.
MAKE_INTR_S32_2OPS(0, smmulr) // Signed Most significant word Multiply and round.
MAKE_INTR_U32_2OPS(1, smuad) // Dual 16-bit Signed Multiply with Addition of products.
MAKE_INTR_U32_2OPS(1, smuadx) // Dual 16-bit Signed Multiply with Addition of products with exchange.
MAKE_INTR_U32_2OPS(0, smulbb) // Signed Multiply, with 16-bit operands (bottom, bottom) and a 32-bit result.
MAKE_INTR_U32_2OPS(0, smulbt) // Signed Multiply, with 16-bit operands (bottom, top) and a 32-bit result.
MAKE_INTR_U32_2OPS(0, smultb) // Signed Multiply, with 16-bit operands (top, bottom) and a 32-bit result.
MAKE_INTR_U32_2OPS(0, smultt) // Signed Multiply, with 16-bit operands (top, top) and a 32-bit result.
// TODO: smull // Signed Long Multiply, with 32-bit operands and 64-bit result.
MAKE_INTR_U32_2OPS(0, smulwb) // Signed Multiply Wide, with one 32-bit and one 16-bit operand (bottom half), providing the top 32 bits of the result.
MAKE_INTR_U32_2OPS(0, smulwt) // Signed Multiply Wide, with one 32-bit and one 16-bit operand (top half), providing the top 32 bits of the result.
/* Doesn't affect any flags? */ MAKE_INTR_U32_2OPS(0, smusd) // Dual 16-bit Signed Multiply with Subtraction of products.
/* Doesn't affect any flags? */ MAKE_INTR_U32_2OPS(0, smusdx) // Dual 16-bit Signed Multiply with Subtraction of products with exchange.
// Signed Saturate to any bit position, with optional shift before saturating.
#define __ssat(op1, op2) \
({ \
s32 __res; \
__asm__ volatile("ssat %0, %1, %2" : "=r" (__res) : "I" (op1), "r" (op2) : "cc"); \
__res; \
})
// Parallel halfword Saturate.
#define __ssat16(op1, op2) \
({ \
u32 __res; \
__asm__ volatile("ssat16 %0, %1, %2" : "=r" (__res) : "I" (op1), "r" (op2) : "cc"); \
__res; \
})
MAKE_INTR_U32_2OPS(1, ssax) // Signed parallel subtract and add halfwords with exchange.
MAKE_INTR_U32_2OPS(1, ssub8) // Signed parallel byte-wise subtraction.
MAKE_INTR_U32_2OPS(1, ssub16) // Signed parallel halfword-wise subtraction.
MAKE_INTR_U32_2OPS(0, sxtab) // Sign extend Byte with Add, to extend an 8-bit value to a 32-bit value.
MAKE_INTR_U32_2OPS(0, sxtab16) // Sign extend two Bytes with Add, to extend two 8-bit values to two 16-bit values.
MAKE_INTR_U32_2OPS(0, sxtah) // Sign extend Halfword with Add, to extend a 16-bit value to a 32-bit value.
MAKE_INTR_U32_1OP(0, sxtb) // Sign extend Byte, to extend an 8-bit value to a 32-bit value.
MAKE_INTR_U32_1OP(0, sxtb16) // Sign extend two bytes.
MAKE_INTR_U32_1OP(0, sxth) // Sign extend Halfword.
MAKE_INTR_U32_2OPS(1, uadd8) // Unsigned parallel byte-wise addition.
MAKE_INTR_U32_2OPS(1, uadd16) // Unsigned parallel halfword-wise addition.
MAKE_INTR_U32_2OPS(1, uasx) // Unsigned parallel add and subtract halfwords with exchange.
MAKE_INTR_U32_2OPS(0, uhadd8) // Unsigned halving parallel byte-wise addition.
MAKE_INTR_U32_2OPS(0, uhadd16) // Unsigned halving parallel halfword-wise addition.
MAKE_INTR_U32_2OPS(0, uhasx) // Unsigned halving parallel add and subtract halfwords with exchange.
MAKE_INTR_U32_2OPS(0, uhsax) // Unsigned halving parallel subtract and add halfwords with exchange.
MAKE_INTR_U32_2OPS(0, uhsub8) // Unsigned halving parallel byte-wise subtraction.
MAKE_INTR_U32_2OPS(0, uhsub16) // Unsigned halving parallel halfword-wise subtraction.
MAKE_INTR_U32_2OPS(0, uqadd8) // Unsigned saturating parallel byte-wise addition.
MAKE_INTR_U32_2OPS(0, uqadd16) // Unsigned saturating parallel halfword-wise addition.
MAKE_INTR_U32_2OPS(0, uqasx) // Unsigned saturating parallel add and subtract halfwords with exchange.
MAKE_INTR_U32_2OPS(0, uqsax) // Unsigned saturating parallel subtract and add halfwords with exchange.
MAKE_INTR_U32_2OPS(0, uqsub8) // Unsigned saturating parallel byte-wise subtraction.
MAKE_INTR_U32_2OPS(0, uqsub16) // Unsigned saturating parallel halfword-wise subtraction.
MAKE_INTR_U32_2OPS(0, usad8) // Unsigned Sum of Absolute Differences.
MAKE_INTR_U32_3OPS(0, usada8) // Unsigned Sum of Absolute Differences and Accumulate.
// Unsigned Saturate to any bit position, with optional shift before saturating.
#define __usat(op1, op2) \
({ \
u32 __res; \
__asm__ volatile("usat %0, %1, %2" : "=r" (__res) : "I" (op1), "r" (op2) : "cc"); \
__res; \
})
// Parallel halfword Saturate.
#define __usat16(op1, op2) \
({ \
u32 __res; \
__asm__ volatile("usat16 %0, %1, %2" : "=r" (__res) : "I" (op1), "r" (op2) : "cc"); \
__res; \
})
MAKE_INTR_U32_2OPS(1, usax) // Unsigned parallel subtract and add halfwords with exchange.
MAKE_INTR_U32_2OPS(1, usub8) // Unsigned parallel byte-wise subtraction.
MAKE_INTR_U32_2OPS(1, usub16) // Unsigned parallel halfword-wise subtraction.
//MAKE_INTR_U32_2OPS(0, uxtab) // Zero extend Byte and Add.
MAKE_INTR_U32_2OPS(0, uxtab16) // Zero extend two Bytes and Add.
//MAKE_INTR_U32_2OPS(0, uxtah) // Zero extend Halfword and Add.
//MAKE_INTR_U32_1OP(0, uxtb) // Zero extend Byte.
MAKE_INTR_U32_1OP(0, uxtb16) // Zero extend two Bytes.
//MAKE_INTR_U32_1OP(0, uxth) // Zero extend Halfword.
#undef MAKE_INTR_U32_1OP
#undef MAKE_INTR_U32_2OPS
#undef MAKE_INTR_U32_3OPS

46
include/asm_macros.h Normal file
View File

@ -0,0 +1,46 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !__ASSEMBLER__
#error Only include this in assembly files!
#endif
.macro BEGIN_ASM_FUNC name, type=arm, linkage=global, section=text
.section .\section\().\name, "ax", %progbits
.if \type == thumb
.align 1
.thumb
.else
.align 2
.arm
.endif
.\linkage \name
.type \name, %function
.func \name
.cfi_sections .debug_frame
.cfi_startproc
\name:
.endm
.macro END_ASM_FUNC
.cfi_endproc
.endfunc
.endm

57
include/error_codes.h Normal file
View File

@ -0,0 +1,57 @@
#pragma once
#include "types.h"
#define CUSTOM_ERR_OFFSET (200u)
#define MAKE_CUSTOM_ERR(e) (CUSTOM_ERR_OFFSET + (e))
typedef u32 Result;
// Keep errors in the range of 0-255.
enum
{
// Common errors.
RES_OK = 0u,
RES_SD_CARD_REMOVED = 1u,
RES_DISK_FULL = 2u,
RES_INVALID_ARG = 3u,
RES_OUT_OF_MEM = 4u,
RES_OUT_OF_RANGE = 5u,
RES_NOT_FOUND = 6u,
// fatfs errors.
// Caution: Update fres2Res() in fs.c on ARM9 if this changes!
RES_FR_DISK_ERR = 7u, /* (1) A hard error occurred in the low level disk I/O layer */
RES_FR_INT_ERR = 8u, /* (2) Assertion failed */
RES_FR_NOT_READY = 9u, /* (3) The physical drive cannot work */
RES_FR_NO_FILE = 10u, /* (4) Could not find the file */
RES_FR_NO_PATH = 11u, /* (5) Could not find the path */
RES_FR_INVALID_NAME = 12u, /* (6) The path name format is invalid */
RES_FR_DENIED = 13u, /* (7) Access denied due to prohibited access or directory full */
RES_FR_EXIST = 14u, /* (8) Access denied due to prohibited access */
RES_FR_INVALID_OBJECT = 15u, /* (9) The file/directory object is invalid */
RES_FR_WRITE_PROTECTED = 16u, /* (10) The physical drive is write protected */
RES_FR_INVALID_DRIVE = 17u, /* (11) The logical drive number is invalid */
RES_FR_NOT_ENABLED = 18u, /* (12) The volume has no work area */
RES_FR_NO_FILESYSTEM = 19u, /* (13) There is no valid FAT volume */
RES_FR_MKFS_ABORTED = 20u, /* (14) The f_mkfs() aborted due to any problem */
RES_FR_TIMEOUT = 21u, /* (15) Could not get a grant to access the volume within defined period */
RES_FR_LOCKED = 22u, /* (16) The operation is rejected according to the file sharing policy */
RES_FR_NOT_ENOUGH_CORE = 23u, /* (17) LFN working buffer could not be allocated */
RES_FR_TOO_MANY_OPEN_FILES = 24u, /* (18) Number of open files > FF_FS_LOCK */
RES_FR_INVALID_PARAMETER = 25u, /* (19) Given parameter is invalid */
// Custom errors.
RES_ROM_TOO_BIG = MAKE_CUSTOM_ERR(0),
RES_GBA_RTC_ERR = MAKE_CUSTOM_ERR(1)
};
#undef MAKE_CUSTOM_ERR
#ifdef ARM11
void printError(Result res);
void printErrorWaitInput(Result res, u32 waitKeys);
#endif

32
include/fb_assert.h Normal file
View File

@ -0,0 +1,32 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#ifdef NDEBUG
#define fb_assert(c) ((void)0)
#else
#define fb_assert(c) ((c) ? ((void)0) : __fb_assert(#c ", " __FILE__, __LINE__))
#endif
noreturn void __fb_assert(const char *const str, u32 line);

64
include/fs.h Normal file
View File

@ -0,0 +1,64 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#include "error_codes.h"
#include "fatfs/ff.h"
#define FS_MAX_DRIVES (FF_VOLUMES)
#define FS_DRIVE_NAMES "sdmc:/"
#define FS_MAX_FILES (1u)
#define FS_MAX_DIRS (1u)
typedef enum
{
FS_DRIVE_SDMC = 0u
} FsDrive;
typedef u32 FHandle;
typedef u32 DHandle;
Result fMount(FsDrive drive);
Result fUnmount(FsDrive drive);
Result fGetFree(FsDrive drive, u64 *const size);
Result fOpen(FHandle *const hOut, const char *const path, u8 mode);
Result fRead(FHandle h, void *const buf, u32 size, u32 *const bytesRead);
Result fWrite(FHandle h, const void *const buf, u32 size, u32 *const bytesWritten);
Result fSync(FHandle h);
Result fLseek(FHandle h, u32 off);
u32 fTell(FHandle h);
u32 fSize(FHandle h);
Result fClose(FHandle h);
Result fStat(const char *const path, FILINFO *const fi);
Result fChdir(const char *const path);
Result fOpenDir(DHandle *const hOut, const char *const path);
Result fReadDir(DHandle h, FILINFO *const fi, u32 num, u32 *const entriesRead);
Result fCloseDir(DHandle h);
Result fMkdir(const char *const path);
Result fRename(const char *const old, const char *const _new);
Result fUnlink(const char *const path);
#ifdef ARM9
void fsDeinit(void);
#endif // ifdef ARM9

28
include/fsutil.h Normal file
View File

@ -0,0 +1,28 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2020 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#include "error_codes.h"
Result fsQuickRead(const char *const path, void *const buf, u32 size);
Result fsQuickWrite(const char *const path, const void *const buf, u32 size);
Result fsMakePath(const char *const path);

32
include/hardware/cache.h Normal file
View File

@ -0,0 +1,32 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
void invalidateICache(void);
void invalidateICacheRange(const void *base, u32 size);
void cleanDCache(void);
void flushDCache(void);
void cleanDCacheRange(const void *base, u32 size);
void flushDCacheRange(const void *base, u32 size);
void invalidateDCache(void);
void invalidateDCacheRange(const void *base, u32 size);

View File

@ -0,0 +1,152 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2019 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
// REG_DMA330_DSR
#define DSR_WAKE_EVNT_SHIFT (4u)
#define DSR_WAKE_EVNT_MASK (0x1Fu<<DSR_WAKEUP_EVNT_SHIFT)
#define DSR_DNS (1u<<9) // DMA Manager is non-secure.
enum
{
DSR_STAT_STOPPED = 0u,
DSR_STAT_EXECUTING = 1u,
DSR_STAT_CACHE_MISS = 2u,
DSR_STAT_UPDATING_PC = 3u, // Updating program counter.
DSR_STAT_WFE = 4u, // Waiting for event.
DSR_STAT_FAULTING = 15u,
DSR_STAT_MASK = DSR_STAT_FAULTING
};
// REG_DMA330_INTEN
#define INTEN_SEL_IRQ(n) (1u<<(n)) // Select IRQ instead of event.
// REG_DMA330_INT_EVENT_RIS
#define INT_EVENT_RIS_ACTIVE(n) (1u<<(n)) // Interrupt or event N is active.
// REG_DMA330_INTMIS
#define INTMIS_IRQ_ACTIVE(n) (1u<<(n)) // Interrupt N is active.
// REG_DMA330_INTCLR
#define INTCLR_IRQ_CLR(n) (1u<<(n)) // Clear interrupt N.
// REG_DMA330_FSRD
#define FSRD_FAULTING (1u) // DMA manager is in faulting state.
// REG_DMA330_FSRC
#define FSRC_FAULTING(n) (1u<<(n)) // DMA channel is in faulting or faulting completing state.
// REG_DMA330_FTRD
#define FTRD_UNDEF_INSTR (1u)
#define FTRD_OPERAND_INVALID (1u<<1)
#define FTRD_DMAGO_ERR (1u<<4) // Starting a secure channel from a non-secure state.
#define FTRD_MGR_EVNT_ERR (1u<<5) // Waiting for or creating secure events/interrupts in no-secure state.
#define FTRD_INSTR_FETCH_ERR (1u<<16)
#define FTRD_DBG_INSTR (1u<<30) // The erroneous instruction came from the debug interface.
// REG_DMA330_FTR0-7
#define FTR_UNDEF_INSTR (1u)
#define FTR_OPERAND_INVALID (1u<<1)
#define FTR_CH_EVNT_ERR (1u<<5) // Waiting for or creating secure events/interrupts in no-secure state.
#define FTR_CH_PERIPH_ERR (1u<<6) // Accessing secure periphals in non-secure state (DMAWFP, DMALDP, DMASTP, DMAFLUSHP).
#define FTR_CH_RDWR_ERR (1u<<7) // Secure read or write in non-secure state.
#define FTR_CH_MFIFO_ERR (1u<<12) // MFIFO too small to hold or store the data (DMALD, DMAST).
#define FTR_CH_ST_DATA_UNAVAIL (1u<<13) // Not enough data in the MFIFO for DMAST to complete.
#define FTR_INSTR_FETCH_ERR (1u<<16)
#define FTR_DATA_WRITE_ERR (1u<<17)
#define FTR_DATA_READ_ERR (1u<<18)
#define FTR_DBG_INSTR (1u<<30) // The erroneous instruction came from the debug interface.
#define FTR_LOCKUP_ERR (1u<<31) // Channel locked up because of resource starvation.
// REG_DMA330_CSR0-7
#define CSR_WAKE_EVNT_SHIFT (4u)
#define CSR_WAKE_EVNT_MASK (0x1Fu<<CSR_WAKEUP_EVNT_SHIFT)
#define CSR_DMAWFP_B_NS (1u<<14) // DMAWFP executed with burst operand set.
#define CSR_DMAWFP_PERIPH (1u<<15) // DMAWFP executed with periph operand set.
#define CSR_CNS (1u<<21) // DMA channel is non-secure.
enum
{
CSR_STAT_STOPPED = 0u,
CSR_STAT_EXECUTING = 1u,
CSR_STAT_CACHE_MISS = 2u,
CSR_STAT_UPDATING_PC = 3u, // Updating program counter.
CSR_STAT_WFE = 4u, // Waiting for event.
CSR_STAT_AT_BARRIER = 5u,
CSR_STAT_WFP = 7u, // Waiting for periphal.
CSR_STAT_KILLING = 8u,
CSR_STAT_COMPLETING = 9u,
CSR_STAT_FAULTING_COMPLETING = 14u,
CSR_STAT_FAULTING = 15u,
CSR_STAT_MASK = CSR_STAT_FAULTING
};
// REG_DMA330_CCR0-7
#define CCR_SRC_INC (1u)
#define CCR_SRC_BURST_SIZE_SHIFT (1u)
#define CCR_SRC_BURST_SIZE_MASK (0x7u<<CCR_SRC_BURST_SIZE_SHIFT)
#define CCR_SRC_BURST_LEN_SHIFT (4u)
#define CCR_SRC_BURST_LEN_MASK (0xFu<<CCR_SRC_BURST_LEN_SHIFT)
#define CCR_SRC_PROT_CTRL_SHIFT (8u)
#define CCR_SRC_PROT_CTRL_MASK (0x7u<<CCR_SRC_PROT_CTRL_SHIFT)
#define CCR_SRC_CACHE_CTRL_SHIFT (11u)
#define CCR_SRC_CACHE_CTRL_MASK (0x7u<<CCR_SRC_CACHE_CTRL_SHIFT)
#define CCR_DST_INC (1u<<14)
#define CCR_DST_BURST_SIZE_SHIFT (15u)
#define CCR_DST_BURST_SIZE_MASK (0x7u<<CCR_DST_BURST_SIZE_SHIFT)
#define CCR_DST_BURST_LEN_SHIFT (18u)
#define CCR_DST_BURST_LEN_MASK (0xFu<<CCR_DST_BURST_LEN_SHIFT)
#define CCR_DST_PROT_CTRL_SHIFT (22u)
#define CCR_DST_PROT_CTRL_MASK (0x7u<<CCR_DST_PROT_CTRL_SHIFT)
#define CCR_DST_CACHE_CTRL_SHIFT (25u)
#define CCR_DST_CACHE_CTRL_MASK (0x7u<<CCR_DST_CACHE_CTRL_SHIFT)
#define CCR_END_SWP_SIZE_SHIFT (28u) // END_SWP_SIZE = endian swap size.
#define CCR_END_SWP_SIZE_MASK (0x7u<<CCR_END_SWP_SIZE_SHIFT)
// REG_DMA330_DBGSTATUS
#define DBGSTATUS_BUSY (1u)
// REG_DMA330_DBGCMD
#define DBGCMD_EXECUTE (0u)
// REG_DMA330_DBGINST0
#define DBGINST0_THR_MGR (0u) // Select DMA manager thread.
#define DBGINST0_THR_CH (1u) // Select DMA channel thread (also needs a channel number).
#define DBGINST0(b10, ch, t) ((b10)<<16 | (ch)<<8 | (t)) // b10 = byte 1 and 0, ch = channel num, t = thread.
// DBGINST1 stores the remaining 4 instruction bytes.
void DMA330_init(void);
u8 DMA330_run(u8 ch, const u8 *const prog);
u8 DMA330_status(u8 ch);
void DMA330_ackIrq(u8 eventIrq);
void DMA330_sev(u8 event);
void DMA330_kill(u8 ch);
#ifdef ARM11
//void DMA330_dbgPrint(void);
#endif // ifdef ARM11

126
include/hardware/gfx.h Normal file
View File

@ -0,0 +1,126 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "mem_map.h"
#include "types.h"
#define SCREEN_TOP (0u)
#define SCREEN_BOT (1u)
#define SCREEN_WIDTH_TOP (400u)
#define SCREEN_HEIGHT_TOP (240u)
#define SCREEN_SIZE_TOP (SCREEN_WIDTH_TOP * SCREEN_HEIGHT_TOP * 2)
#define SCREEN_WIDTH_BOT (320u)
#define SCREEN_HEIGHT_BOT (240u)
#define SCREEN_SIZE_BOT (SCREEN_WIDTH_BOT * SCREEN_HEIGHT_BOT * 2)
// TODO:
// Because we are using a VRAM allocator this may break any time.
#define FRAMEBUF_TOP_A_1 ((void*)VRAM_BASE)
#define FRAMEBUF_BOT_A_1 (FRAMEBUF_TOP_A_1 + SCREEN_SIZE_TOP)
#define FRAMEBUF_TOP_A_2 (FRAMEBUF_BOT_A_1 + SCREEN_SIZE_BOT + SCREEN_SIZE_TOP) // Skip B1
#define FRAMEBUF_BOT_A_2 (FRAMEBUF_TOP_A_2 + SCREEN_SIZE_TOP)
#define DEFAULT_BRIGHTNESS (0x30)
/// Converts packed RGB8 to packed RGB565.
#define RGB8_to_565(r,g,b) (((b)>>3)&0x1f)|((((g)>>2)&0x3f)<<5)|((((r)>>3)&0x1f)<<11)
/// Framebuffer format.
typedef enum
{
GFX_RGBA8 = 0, ///< RGBA8. (4 bytes)
GFX_BGR8 = 1, ///< BGR8. (3 bytes)
GFX_RGB565 = 2, ///< RGB565. (2 bytes)
GFX_RGB5A1 = 3, ///< RGB5A1. (2 bytes)
GFX_RGBA4 = 4 ///< RGBA4. (2 bytes)
} GfxFbFmt;
#ifdef ARM11
typedef enum
{
GFX_EVENT_PSC0 = 0u,
GFX_EVENT_PSC1 = 1u,
GFX_EVENT_PDC0 = 2u,
GFX_EVENT_PDC1 = 3u,
GFX_EVENT_PPF = 4u,
GFX_EVENT_P3D = 5u
} GfxEvent;
typedef enum
{
GFX_BLIGHT_BOT = 1u<<2,
GFX_BLIGHT_TOP = 1u<<4,
GFX_BLIGHT_BOTH = GFX_BLIGHT_TOP | GFX_BLIGHT_BOT
} GfxBlight;
void GFX_init(GfxFbFmt fmtTop, GfxFbFmt fmtBot);
static inline void GFX_initDefault(void)
{
GFX_init(GFX_BGR8, GFX_BGR8);
}
void GFX_deinit(void);
void GFX_setFramebufFmt(GfxFbFmt fmtTop, GfxFbFmt fmtBot);
void GFX_powerOnBacklights(GfxBlight mask);
void GFX_powerOffBacklights(GfxBlight mask);
void GFX_setBrightness(u8 top, u8 bot);
void GFX_setForceBlack(bool top, bool bot);
void GFX_setDoubleBuffering(u8 screen, bool dBuf);
void* GFX_getFramebuffer(u8 screen);
void GFX_swapFramebufs(void);
void GFX_waitForEvent(GfxEvent event, bool discard);
// Helpers
#define GFX_waitForPSC0() GFX_waitForEvent(GFX_EVENT_PSC0, false)
#define GFX_waitForPSC1() GFX_waitForEvent(GFX_EVENT_PSC1, false)
#define GFX_waitForVBlank0() GFX_waitForEvent(GFX_EVENT_PDC0, true)
//#define GFX_waitForVBlank1() GFX_waitForEvent(GFX_EVENT_PDC1, true) // Disabled
#define GFX_waitForPPF() GFX_waitForEvent(GFX_EVENT_PPF, false)
#define GFX_waitForP3D() GFX_waitForEvent(GFX_EVENT_P3D, false)
void GX_memoryFill(u32 *buf0a, u32 buf0v, u32 buf0Sz, u32 val0, u32 *buf1a, u32 buf1v, u32 buf1Sz, u32 val1);
void GX_displayTransfer(const u32 *const in, u32 indim, u32 *out, u32 outdim, u32 flags);
void GX_textureCopy(const u32 *const in, u32 indim, u32 *out, u32 outdim, u32 size);
void GX_processCommandList(u32 size, const u32 *const cmdList);
//void GFX_enterLowPowerState(void);
//void GFX_returnFromLowPowerState(void);
#endif

114
include/hardware/lgy.h Normal file
View File

@ -0,0 +1,114 @@
#pragma once
#include "types.h"
#include "error_codes.h"
#define MAX_ROM_SIZE (1024u * 1024 * 32)
#define MAX_SAVE_SIZE (1024u * 128)
#define ARM7_STUB_LOC (0x3007E00u)
#define ARM7_STUB_LOC9 (0x80BFE00u)
#define ROM_LOC (0x20000000u)
#define SAVE_LOC (0x8080000u)
// REG_LGY_MODE
#define LGY_MODE_TWL (1u)
#define LGY_MODE_AGB (2u)
#define LGY_MODE_START (1u<<15)
// REG_LGY_GBA_SAVE_TYPE
enum
{
SAVE_TYPE_EEPROM_8k = 0x0u, // "[save] in upper 16Mbyte of ROM area"
SAVE_TYPE_EEPROM_8k_2 = 0x1u, // "[save] in upper 100h byte of ROM area"
SAVE_TYPE_EEPROM_64k = 0x2u, // "[save] in upper 16Mbyte of ROM area"
SAVE_TYPE_EEPROM_64k_2 = 0x3u, // "[save] in upper 100h byte of ROM area"
SAVE_TYPE_FLASH_512k_AML_RTC = 0x4u, // "FLASH ID=3D1Fh, Atmel"
SAVE_TYPE_FLASH_512k_AML = 0x5u, // "FLASH ID=3D1Fh, Atmel"
SAVE_TYPE_FLASH_512k_SST_RTC = 0x6u, // "FLASH ID=D4BFh, SST"
SAVE_TYPE_FLASH_512k_SST = 0x7u, // "FLASH ID=D4BFh, SST"
SAVE_TYPE_FLASH_512k_PSC_RTC = 0x8u, // "FLASH ID=1B32h, Panasonic"
SAVE_TYPE_FLASH_512k_PSC = 0x9u, // "FLASH ID=1B32h, Panasonic"
SAVE_TYPE_FLASH_1m_MRX_RTC = 0xAu, // "FLASH ID=09C2h, Macronix"
SAVE_TYPE_FLASH_1m_MRX = 0xBu, // "FLASH ID=09C2h, Macronix"
SAVE_TYPE_FLASH_1m_SNO_RTC = 0xCu, // "FLASH ID=1362h, Sanyo"
SAVE_TYPE_FLASH_1m_SNO = 0xDu, // "FLASH ID=1362h, Sanyo"
SAVE_TYPE_SRAM_256k = 0xEu,
SAVE_TYPE_NONE = 0xFu,
SAVE_TYPE_MASK = SAVE_TYPE_NONE
};
// REG_LGY_GBA_SAVE_MAP
#define LGY_SAVE_MAP_7 (0u)
#define LGY_SAVE_MAP_9 (1u)
// REG_LGY_GBA_RTC_CNT
#define LGY_RTC_CNT_WR (1u) // Write date and time.
#define LGY_RTC_CNT_RD (1u<<1) // Read date and time.
#define LGY_RTC_CNT_WR_ERR (1u<<14) // Write error (wrong date/time).
#define LGY_RTC_CNT_BUSY (1u<<15)
// REG_LGY_GBA_RTC_BCD_DATE
// Shifts
#define LGY_RTC_BCD_Y_SHIFT (0u)
#define LGY_RTC_BCD_MON_SHIFT (8u)
#define LGY_RTC_BCD_D_SHIFT (16u)
#define LGY_RTC_BCD_W_SHIFT (24u)
// Masks
#define LGY_RTC_BCD_Y_MASK (0xFFu<<LGY_RTC_BCD_Y_SHIFT)
#define LGY_RTC_BCD_MON_MASK (0x1Fu<<LGY_RTC_BCD_M_SHIFT)
#define LGY_RTC_BCD_D_MASK (0x3Fu<<LGY_RTC_BCD_D_SHIFT)
#define LGY_RTC_BCD_W_MASK (0x07u<<LGY_RTC_BCD_W_SHIFT)
// REG_LGY_GBA_RTC_BCD_TIME
// Shifts
#define LGY_RTC_BCD_H_SHIFT (0u)
#define LGY_RTC_BCD_MIN_SHIFT (8u)
#define LGY_RTC_BCD_S_SHIFT (16u)
// Masks
#define LGY_RTC_BCD_H_MASK (0x3Fu<<LGY_RTC_BCD_H_SHIFT)
#define LGY_RTC_BCD_MIN_MASK (0x7Fu<<LGY_RTC_BCD_MIN_SHIFT)
#define LGY_RTC_BCD_S_MASK (0x7Fu<<LGY_RTC_BCD_S_SHIFT)
// All values in BCD.
typedef struct
{
union
{
struct
{
u8 h;
u8 min;
u8 s;
u8 unused;
};
u32 time;
};
union
{
struct
{
u8 y;
u8 mon;
u8 d;
u8 dow; // Day of week.
};
u32 date;
};
} ALIGN(8) GbaRtc; // Workaround: Poor optimization on pass by value.
// REGs_LGY_GBA_SAVE_TIMING
Result LGY_prepareGbaMode(bool biosIntro, u16 saveType, const char *const savePath);
Result LGY_setGbaRtc(const GbaRtc rtc);
Result LGY_getGbaRtc(GbaRtc *const out);
Result LGY_backupGbaSave(void);
#ifdef ARM11
void LGY_switchMode(void);
void LGY_handleOverrides(void);
void LGY_deinit(void);
#endif

73
include/hardware/pxi.h Normal file
View File

@ -0,0 +1,73 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#include "mem_map.h"
#ifdef ARM9
#define PXI_REGS_BASE (IO_MEM_ARM9_ONLY + 0x8000)
#elif ARM11
#define PXI_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x63000)
#endif
#define REG_PXI_SYNC_RECVD *((const vu8*)(PXI_REGS_BASE + 0x00))
#define REG_PXI_SYNC_SENT *((vu8 *)(PXI_REGS_BASE + 0x01)) // Write-only
#define REG_PXI_SYNC_IRQ *((vu8 *)(PXI_REGS_BASE + 0x03))
#define REG_PXI_SYNC *((vu32*)(PXI_REGS_BASE + 0x00))
#define REG_PXI_CNT *((vu16*)(PXI_REGS_BASE + 0x04))
#define REG_PXI_SFIFO *((vu32*)(PXI_REGS_BASE + 0x08))
#define REG_PXI_RFIFO *((const vu32*)(PXI_REGS_BASE + 0x0C))
// REG_PXI_SYNC
#define PXI_SYNC_RECVD (REG_PXI_SYNC & 0xFFu)
#define PXI_SYNC_SENT(sent) ((REG_PXI_SYNC & ~(0xFFu<<8)) | (sent)<<8)
#ifdef ARM9
#define PXI_SYNC_IRQ (1u<<29)
#elif ARM11
#define PXI_SYNC_IRQ (1u<<30)
#endif
#define PXI_SYNC_IRQ_ENABLE (1u<<31)
// REG_PXI_SYNC_IRQ
#ifdef ARM9
#define PXI_SYNC_IRQ_IRQ (1u<<5)
#define PXI_SYNC_IRQ_IRQ2 (1u<<6)
#elif ARM11
#define PXI_SYNC_IRQ_IRQ (1u<<6)
#endif
#define PXI_SYNC_IRQ_IRQ_ENABLE (1u<<7)
// REG_PXI_CNT
#define PXI_CNT_SFIFO_EMPTY (1u<<0)
#define PXI_CNT_SFIFO_FULL (1u<<1)
#define PXI_CNT_SFIFO_NOT_FULL_IRQ_ENABLE (1u<<2)
#define PXI_CNT_FLUSH_SFIFO (1u<<3)
#define PXI_CNT_RFIFO_EMPTY (1u<<8)
#define PXI_CNT_RFIFO_FULL (1u<<9)
#define PXI_CNT_RFIFO_NOT_EMPTY_IRQ_ENABLE (1u<<10)
#define PXI_CNT_FIFO_ERROR (1u<<14) // Also used for aknowledge
#define PXI_CNT_ENABLE_SRFIFO (1u<<15)
void PXI_init(void);
u32 PXI_sendCmd(u32 cmd, const u32 *buf, u32 words);
void PXI_sendPanicCmd(u32 cmd); // Not intended for normal use!

92
include/ipc_handler.h Normal file
View File

@ -0,0 +1,92 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#define IPC_MAX_PARAMS (15)
#define IPC_CMD_RESP_FLAG (1u<<15)
#define IPC_CMD_ID_MASK(cmd) ((cmd)>>8) // Max 127
#define IPC_CMD_IN_BUFS_MASK(cmd) ((cmd)>>6 & 3u) // Max 3
#define IPC_CMD_OUT_BUFS_MASK(cmd) ((cmd)>>4 & 3u) // Max 3
#define IPC_CMD_PARAMS_MASK(cmd) ((cmd) & 15u) // Max 15
// https://stackoverflow.com/a/52770279
// Note: __COUNTER__ is non standard.
#define MAKE_CMD9(inBufs, outBufs, params) ((__COUNTER__ - _CMD9_C_BASE)<<8 | (inBufs)<<6 | (outBufs)<<4 | params)
#define MAKE_CMD11(inBufs, outBufs, params) ((__COUNTER__ - _CMD11_C_BASE)<<8 | (inBufs)<<6 | (outBufs)<<4 | params)
enum {_CMD9_C_BASE = __COUNTER__ + 1}; // Start at 0.
typedef enum
{
// Filesystem API.
IPC_CMD9_FMOUNT = MAKE_CMD9(0, 0, 1),
IPC_CMD9_FUNMOUNT = MAKE_CMD9(0, 0, 1),
IPC_CMD9_FGETFREE = MAKE_CMD9(0, 1, 1),
IPC_CMD9_FOPEN = MAKE_CMD9(1, 1, 1),
IPC_CMD9_FREAD = MAKE_CMD9(0, 2, 1),
IPC_CMD9_FWRITE = MAKE_CMD9(1, 1, 1),
IPC_CMD9_FSYNC = MAKE_CMD9(0, 0, 1),
IPC_CMD9_FLSEEK = MAKE_CMD9(0, 0, 2),
IPC_CMD9_FTELL = MAKE_CMD9(0, 0, 1),
IPC_CMD9_FSIZE = MAKE_CMD9(0, 0, 1),
IPC_CMD9_FCLOSE = MAKE_CMD9(0, 0, 1),
IPC_CMD9_FSTAT = MAKE_CMD9(1, 1, 0),
IPC_CMD9_FCHDIR = MAKE_CMD9(1, 0, 0),
IPC_CMD9_FOPEN_DIR = MAKE_CMD9(1, 1, 0),
IPC_CMD9_FREAD_DIR = MAKE_CMD9(0, 2, 2),
IPC_CMD9_FCLOSE_DIR = MAKE_CMD9(0, 0, 1),
IPC_CMD9_FMKDIR = MAKE_CMD9(1, 0, 0),
IPC_CMD9_FRENAME = MAKE_CMD9(2, 0, 0),
IPC_CMD9_FUNLINK = MAKE_CMD9(1, 0, 0),
// open_agb_firm specific API.
IPC_CMD9_PREPARE_GBA = MAKE_CMD9(1, 0, 2),
IPC_CMD9_SET_GBA_RTC = MAKE_CMD9(0, 0, 2),
IPC_CMD9_GET_GBA_RTC = MAKE_CMD9(0, 1, 0),
IPC_CMD9_BACKUP_GBA_SAVE = MAKE_CMD9(0, 0, 0),
// Miscellaneous API.
IPC_CMD9_PREPARE_POWER = MAKE_CMD9(0, 0, 0) // Also used for panic() and guruMeditation().
} IpcCmd9;
enum {_CMD11_C_BASE = __COUNTER__ + 1}; // Start at 0.
typedef enum
{
// Miscellaneous API.
IPC_CMD11_PRINT_MSG = MAKE_CMD11(0, 0, 0), // Invalid on purpose. Will be decided later.
IPC_CMD11_PANIC = MAKE_CMD11(0, 0, 0),
IPC_CMD11_EXCEPTION = MAKE_CMD11(0, 0, 0)
} IpcCmd11;
#undef MAKE_CMD9
#undef MAKE_CMD11
typedef struct
{
void *ptr;
u32 size;
} IpcBuffer;
u32 IPC_handleCmd(u8 cmdId, u32 inBufs, u32 outBufs, const u32 *const buf);

153
include/mem_map.h Normal file
View File

@ -0,0 +1,153 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef ARM9
/* ITCM */
#define ITCM_BASE (0x00000000)
#define ITCM_KERNEL_MIRROR (0x01FF8000)
#define ITCM_BOOT9_MIRROR (0x07FF8000)
#define ITCM_SIZE (0x00008000) // 32 KiB
#endif
#ifdef ARM11
/* ARM11 bootrom */
#define BOOT11_BASE (0x00000000)
#define BOOT11_MIRROR1 (0x00010000)
#define BOOT11_SIZE (0x00010000) // 64 KiB
#endif
#ifdef ARM9
/* ARM9 RAM */
#define A9_RAM_BASE (0x08000000)
#define A9_RAM_N3DS_EXT_BASE (A9_RAM_BASE + 0x100000)
#define A9_RAM_SIZE (0x00100000) // 1 MiB
#define A9_RAM_N3DS_EXT_SIZE (0x00080000) // 512 KiB
#endif
/* IO mem */
#define IO_MEM_BASE (0x10000000)
#define IO_MEM_ARM9_ONLY (IO_MEM_BASE)
#define IO_MEM_ARM9_ARM11 (IO_MEM_BASE + 0x100000)
#define IO_MEM_ARM11_ONLY (IO_MEM_BASE + 0x200000)
#ifdef ARM11
/* ARM11 MPCore private region */
#define MPCORE_PRIV_REG_BASE (0x17E00000)
#define MPCORE_PRIV_REG_SIZE (0x00002000) // 8 KiB
/* L2C-310 Level 2 Cache Controller */
#define L2_CACHE_CONTR_BASE (0x17E10000)
#define L2_CACHE_CONTR_SIZE (0x00001000) // 4 KiB
#endif
/* VRAM */
#define VRAM_BASE (0x18000000)
#define VRAM_SIZE (0x00600000)
#define VRAM_BANK0 (VRAM_BASE)
#define VRAM_BANK1 (VRAM_BASE + 0x300000)
/* DSP mem */
#define DSP_MEM_BASE (0x1FF00000)
#define DSP_MEM_SIZE (0x00080000) // 512 KiB
/* AXIWRAM */
#define AXIWRAM_BASE (0x1FF80000)
#define AXIWRAM_SIZE (0x00080000) // 512 KiB
/* FCRAM */
#define FCRAM_BASE (0x20000000)
#define FCRAM_N3DS_EXT_BASE (FCRAM_BASE + 0x8000000)
#define FCRAM_SIZE (0x08000000) // 128 MiB
#define FCRAM_N3DS_EXT_SIZE (FCRAM_SIZE)
#ifdef ARM9
/* OTP */
#define OTP_BASE (0x10012000)
#define OTP_SIZE (0x00000100) // 256 bytes
/* DTCM */
#define DTCM_BASE (0xFFF00000)
#define DTCM_SIZE (0x00004000) // 16 KiB
/* ARM9 bootrom */
#define BOOT9_BASE (0xFFFF0000)
#define BOOT9_SIZE (0x00010000) // 64 KiB
#endif
#ifdef ARM11
/* ARM11 bootrom */
#define BOOT11_MIRROR2 (0xFFFF0000)
#endif
/* Custom mappings */
#ifdef ARM9
#define A9_VECTORS_START (A9_RAM_BASE)
#define A9_VECTORS_SIZE (0x40)
#define A9_STUB_ENTRY (ITCM_KERNEL_MIRROR + ITCM_SIZE - 0x200)
#define A9_STUB_SIZE (0x200)
#define A9_HEAP_END (A9_RAM_BASE + A9_RAM_SIZE)
#define A9_STACK_START (DTCM_BASE)
#define A9_STACK_END (DTCM_BASE + DTCM_SIZE - 0x400)
#define A9_IRQ_STACK_START (DTCM_BASE + DTCM_SIZE - 0x400)
#define A9_IRQ_STACK_END (DTCM_BASE + DTCM_SIZE)
#define A9_EXC_STACK_START (ITCM_KERNEL_MIRROR + (ITCM_SIZE / 2))
#define A9_EXC_STACK_END (ITCM_KERNEL_MIRROR + ITCM_SIZE)
#define FIRM_LOAD_ADDR (VRAM_BASE + 0x200000)
#define RAM_FIRM_BOOT_ADDR (FCRAM_BASE + 0x1000)
#endif
#ifdef ARM11
#define A11_C0_STACK_START (AXIWRAM_BASE) // Core 0 stack
#define A11_C0_STACK_END (A11_C0_STACK_START + 0x2000)
#define A11_C1_STACK_START (A11_C0_STACK_END) // Core 1 stack
#define A11_C1_STACK_END (A11_C1_STACK_START + 0x2000)
// WARNING: The stacks for core 2/3 are temporary
#define A11_C2_STACK_START (FCRAM_BASE - 0x600) // Core 2 stack
#define A11_C2_STACK_END (FCRAM_BASE - 0x400)
#define A11_C3_STACK_START (FCRAM_BASE - 0x400) // Core 3 stack
#define A11_C3_STACK_END (FCRAM_BASE - 0x200)
#define A11_EXC_STACK_START (VRAM_BASE + VRAM_SIZE - 0x200000)
#define A11_EXC_STACK_END (VRAM_BASE + VRAM_SIZE - 0x100000)
#define A11_MMU_TABLES_BASE (A11_C1_STACK_END)
#define A11_VECTORS_START (AXIWRAM_BASE + AXIWRAM_SIZE - 0x60)
#define A11_VECTORS_SIZE (0x60)
#define A11_FALLBACK_ENTRY (AXIWRAM_BASE + AXIWRAM_SIZE - 0x4)
#define A11_STUB_ENTRY (AXIWRAM_BASE + AXIWRAM_SIZE - 0x200)
#define A11_STUB_SIZE (0x1A0) // Don't overwrite the vectors
#define A11_HEAP_END (AXIWRAM_BASE + AXIWRAM_SIZE)
#endif

28
include/mmio.h Normal file
View File

@ -0,0 +1,28 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2019 Aurora Wright, TuxSH, derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Based on https://github.com/AuroraWright/Luma3DS/blob/master/arm9/source/alignedseqmemcpy.s
#include "types.h"
void iomemcpy(vu32 *restrict dst, const vu32 *restrict src, u32 size);
void iomemset(vu32 *ptr, u32 value, u32 size);

View File

@ -1,8 +1,8 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2024 profi200
* This file is part of fastboot 3DS
* Copyright (C) 2018 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -18,16 +18,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#ifdef __cplusplus
extern "C"
{
#endif
void convert160pFrameFast(void);
void convert240pFrameFast(void);
#ifdef __cplusplus
} // extern "C"
#endif
//void WEAK __systemInit(void);
void WEAK __systemDeinit(void);

77
include/types.h Normal file
View File

@ -0,0 +1,77 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <inttypes.h> // printf()/scanf() macros
#include <stdalign.h> // alignas(alignment_in_bytes)
#include <stdbool.h> // bool, true/false
#include <stddef.h> // size_t, NULL...
#include <stdint.h> // uint8_t, uint16_t...
#include <stdnoreturn.h> // noreturn keyword
#include <unistd.h> // ssize_t
#define ALIGN(a) __attribute__((aligned(a))) // Use alignas() instead.
#define NAKED __attribute__((naked))
#define NOINLINE __attribute__((noinline))
#define ALWAYS_INLINE __attribute__((always_inline)) static inline
#define PACKED __attribute__((packed))
#define TARGET_ARM __attribute__((target("arm")))
#define TARGET_THUMB __attribute__((target("thumb")))
#define UNUSED __attribute__((unused))
#define USED __attribute__((used))
#define WEAK __attribute__((weak))
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;
typedef int64_t s64;
typedef volatile uint8_t vu8;
typedef volatile uint16_t vu16;
typedef volatile uint32_t vu32;
typedef volatile uint64_t vu64;
typedef volatile int8_t vs8;
typedef volatile int16_t vs16;
typedef volatile int32_t vs32;
typedef volatile int64_t vs64;
typedef struct
{
u32 data[3];
} _u96;
typedef struct
{
u32 data[4];
} _u128;
typedef struct
{
u32 data[16];
} _u512;

97
include/util.h Normal file
View File

@ -0,0 +1,97 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#define min(a,b) ((size_t) (a) <= (size_t) (b) ? (size_t) (a) : (size_t) (b))
#define arrayEntries(array) sizeof(array)/sizeof(*array)
/**
* @brief Waits at least the specified amount of CPU cycles.
*
* @param[in] cycles The cycles to wait.
*/
NAKED void wait_cycles(u32 cycles);
/**
* @brief Safer strcpy with checks.
* The dst string always gets terminated except when num is 0.
* If the src string is too long nothing is copied and dst will be terminated.
* This function is not safe against race conditions!
*
* @param dst The destination pointer.
* @param[in] src The source pointer.
* @param[in] num Maximum number of chars to copy including null terminator.
*
* @return The length of the copied string in bytes including null terminator.
*/
size_t safeStrcpy(char *const dst, const char *const src, size_t num);
/**
* @brief Basic string to float conversion. Limited to 6 decimal places.
* Doesn't support exponents.
*
* @param[in] str The string.
*
* @return The floatingpoint number represented by str.
*/
float str2float(const char *str);
// case insensitive string compare function
int strnicmp(const char *str1, const char *str2, u32 len);
// custom safe strncpy, string is always 0-terminated for buflen > 0
void strncpy_s(char *dest, const char *src, u32 nchars, const u32 buflen);
void memcpy_s(void *dstBuf, size_t dstBufSize, size_t dstBufOffset,
void *srcBuf, size_t srcBufSize, size_t srcBufOffset, bool reverse);
u32 getleu32(const void* ptr);
u32 swap32(u32 val);
static inline u32 intLog2(u32 val)
{
// The result is undefined if __builtin_clz() is called with 0.
return (val ? 31u - __builtin_clz(val) : 0u);
}
// Round up to the next power of 2.
static inline u32 nextPow2(u32 val)
{
// Portable variant:
// https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
/*val--;
val |= val>>1;
val |= val>>2;
val |= val>>4;
val |= val>>8;
val |= val>>16;
val++;
return val;*/
// Warning: Allowed range is 2 - 2147483648.
// Everything else is undefined behavior.
return 1u<<(32u - __builtin_clz(val - 1));
}

View File

@ -1,8 +1,8 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2022 derrek, profi200
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -18,36 +18,23 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "error_codes.h"
// MAX_PRIO_BITS The number of available priorities. Minimum 3. Maximum 32.
#define MAX_PRIO_BITS (4)
/*
* Maximum number of objects we can create (Slabheap).
*/
#define MAX_TASKS (3) // Including main and idle task.
#define MAX_EVENTS (10)
#define MAX_MUTEXES (3)
#define MAX_SEMAPHORES (0)
#define MAX_TIMERS (0)
#define IDLE_STACK_SIZE (0x1000) // Keep in mind this stack is used in interrupt contex! TODO: Change this.
#ifdef __cplusplus
extern "C"
{
#endif
#define MAKE_CUSTOM_ERR(e) (CUSTOM_ERR_OFFSET + (e))
// Keep errors in the range of 0-CUSTOM_ERR_OFFSET - 1.
enum
{
// Custom errors.
RES_ROM_TOO_BIG = MAKE_CUSTOM_ERR(0u),
RES_INVALID_PATCH = MAKE_CUSTOM_ERR(1u),
MAX_OAF_RES_VALUE = RES_ROM_TOO_BIG
};
#undef MAKE_CUSTOM_ERR
const char* oafResult2String(Result res);
#ifdef __ARM11__
void printError(Result res);
void printErrorWaitInput(Result res, u32 waitKeys);
#endif // ifdef __ARM11__
#ifdef __cplusplus
} // extern "C"
// TODO: More checks. For example slabheap.
#if (MAX_PRIO_BITS < 3 || MAX_PRIO_BITS > 32)
#error "Invalid number of maximum task priorities!"
#endif

View File

@ -0,0 +1,49 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#include "kernel.h"
#ifdef __cplusplus
extern "C"
{
#endif
typedef struct
{
u32 r4;
u32 r5;
u32 r6;
u32 r7;
u32 r8;
u32 r9;
u32 r10;
u32 r11;
u32 lr; // pc
} cpuRegs;
KRes switchContext(KRes res, uintptr_t *oldSp, uintptr_t newSp);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,60 @@
#pragma once
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include "types.h"
#include "internal/list.h"
#include "kernel.h"
#include "arm.h"
typedef enum
{
TASK_STATE_DEAD = 0,
//TASK_STATE_READY = 1,
TASK_STATE_RUNNING = 1,
TASK_STATE_BLOCKED = 2,
TASK_STATE_RUNNING_SHORT = 3 // Continue task as soon as the woken ones are finished.
} TaskState;
struct TaskCb
{
ListNode node;
u8 core; // TODO: Multicore
u8 prio;
u8 id;
KRes res; // Last error code. Also abused for taskArg.
uintptr_t savedSp;
void *stack;
// Name?
// Exit code?
}; // Task context
typedef struct TaskCb TaskCb;
static_assert(offsetof(TaskCb, node) == 0, "Error: Member node of TaskCb is not at offset 0!");
const TaskCb* getCurrentTask(void);
KRes waitQueueBlock(ListNode *waitQueue);
bool waitQueueWakeN(ListNode *waitQueue, u32 wakeCount, KRes res, bool reschedule);
static inline void kernelLock(void)
{
__cpsid(i);
//spinlockLock(&g_lock);
}
static inline void kernelUnlock(void)
{
__cpsie(i);
//spinlockUnlock(&g_lock);
}
// These functions belong in other headers however we
// don't want to make them accessible in the public API.
void _eventSlabInit(void);
void _mutexSlabInit(void);
void _semaphoreSlabInit(void);
void _timerInit(void);

View File

@ -0,0 +1,35 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2019 Aurora Wright, TuxSH, derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Based on https://github.com/AuroraWright/Luma3DS/blob/master/arm9/source/alignedseqmemcpy.s
#include "types.h"
void kmemcpy(u32 *restrict dst, const u32 *restrict src, u32 size);
// Alias of kmemcpy() with volatile arguments.
void iokmemcpy(vu32 *restrict dst, const vu32 *restrict src, u32 size);
void kmemset(u32 *ptr, u32 value, u32 size);
// Alias of kmemset() with volatile arguments.
void iokmemset(vu32 *ptr, u32 value, u32 size);

View File

@ -0,0 +1,103 @@
#pragma once
// Based on https://github.com/torvalds/linux/blob/master/include/linux/list.h
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#define LIST_INIT_VAL(name) ((ListNode){&(name), &(name)})
#define LIST_ENTRY(ptr, type, member) \
({ \
void *__mptr = (void*)(ptr); \
(type*)(__mptr - (size_t)&((type*)0)->member); \
})
#define LIST_FIRST_ENTRY(ptr, type, member) \
LIST_ENTRY((ptr)->next, type, member)
#define LIST_NEXT_ENTRY(pos, member) \
LIST_ENTRY((pos)->member.next, typeof(*(pos)), member)
#define LIST_FOR_EACH_ENTRY(pos, start, member) \
for(pos = LIST_FIRST_ENTRY(start, typeof(*pos), member); \
&pos->member != (start); \
pos = LIST_NEXT_ENTRY(pos, member))
typedef struct ListNode ListNode;
struct ListNode
{
ListNode *next;
ListNode *prev;
};
//static_assert(offsetof(ListNode, next) == 0, "Error: Member next of ListNode is not at offset 0!");
static inline void listInit(ListNode *start)
{
*start = LIST_INIT_VAL(*start);
}
static inline bool listEmpty(const ListNode *start)
{
return start->next == start;
}
// Internal function. Don't use unless you know what you are doing!
static inline void _listAdd(ListNode *node, ListNode *next, ListNode *prev)
{
node->next = next;
node->prev = prev;
next->prev = node;
prev->next = node;
}
static inline void listAddBefore(ListNode *entry, ListNode *node)
{
_listAdd(node, entry, entry->prev);
}
static inline void listAddAfter(ListNode *entry, ListNode *node)
{
_listAdd(node, entry->next, entry);
}
// Internal function. Don't use unless you know what you are doing!
static inline void _listDelete(ListNode *next, ListNode *prev)
{
next->prev = prev;
prev->next = next;
}
static inline void listDelete(ListNode *entry)
{
_listDelete(entry->next, entry->prev);
}
static inline ListNode* listRemoveTail(ListNode *start)
{
ListNode *const node = start->next;
listDelete(node);
return node;
}
static inline ListNode* listRemoveHead(ListNode *start)
{
ListNode *const node = start->prev;
listDelete(node);
return node;
}
// Some function aliases for queues.
#define listPush(start, node) listAddBefore((start), (node))
#define listPop(start) listRemoveTail((start))
#define listPushTail(start, node) listAddAfter((start), (node))
#define listPopHead(start) listRemoveHead((start))

View File

@ -0,0 +1,46 @@
#pragma once
#include <stddef.h>
#include "internal/list.h"
typedef ListNode SlabHeap;
/**
* @brief Initializes the slabheap.
*
* @param slab SlabHeap object pointer.
* @param[in] objSize The size of the object slots.
* @param[in] num The maximum number of object slots.
*/
void slabInit(SlabHeap *slab, size_t objSize, size_t num);
/**
* @brief Allocates an object slot from the slabheap.
*
* @param slab SlabHeap object pointer.
*
* @return Returns a pointer to the object slot.
*/
void* slabAlloc(SlabHeap *slab);
/**
* @brief Same as slabAlloc() but clears slots.
*
* @param slab SlabHeap object pointer.
* @param[in] clrSize The clear size (passed to memset()).
*
* @return Returns a pointer to the object slot.
*/
void* slabCalloc(SlabHeap *slab, size_t clrSize);
/**
* @brief Deallocates an object slot.
*
* @param slab SlabHeap object pointer.
* @param ptr The object slot pointer.
*/
void slabFree(SlabHeap *slab, void *ptr);

View File

@ -0,0 +1,45 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
static inline void spinlockLock(u32 *lock)
{
u32 tmp;
__asm__ volatile("1: ldrex %0, [%1]\n"
" teq %0, #0\n"
" wfene\n"
" strexeq %0, %2, [%1]\n"
" teqeq %0, #0\n"
" bne 1b\n"
" mcr p15, 0, %0, c7, c10, 5" // DMB
: "=&r" (tmp) : "r" (lock), "r" (1) : "cc", "memory");
}
static inline void spinlockUnlock(u32 *lock)
{
__asm__ volatile("mcr p15, 0, %0, c7, c10, 5\n" // DMB
"str %0, [%1]\n"
"mcr p15, 0, %0, c7, c10, 4\n" // DSB
"sev"
: : "r" (0), "r" (lock) : "memory");
}

View File

@ -0,0 +1,5 @@
#pragma once
#define LIKELY(expr) __builtin_expect((expr), true)
#define UNLIKELY(expr) __builtin_expect((expr), false)

78
kernel/include/kernel.h Normal file
View File

@ -0,0 +1,78 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C"
{
#endif
enum
{
KRES_OK = 0, // No error.
KRES_INVALID_HANDLE = 1, // The handle or object doesn't exist.
KRES_HANDLE_DELETED = 2, // The handle has been deleted externally.
//KRES_WAIT_QUEUE_FULL = 3, // The wait queue is full. We can't block on it.
KRES_WOULD_BLOCK = 3, // The function would block. For non-blocking APIs.
KRES_NO_PERMISSIONS = 4 // You have no permissions. Example unlocking a mutex on a different task.
};
typedef uintptr_t KRes; // See createTask()
typedef struct TaskCb KTask;
typedef void (*TaskFunc)(void*);
/**
* @brief Initializes the kernel. Only call this once.
*
* @param[in] priority The priority of the main task.
*/
void kernelInit(uint8_t priority);
/**
* @brief Creates a new kernel task.
*
* @param[in] stackSize The stack size.
* @param[in] priority The priority.
* @param[in] entry The entry function.
* @param taskArg The task entry function argument.
*
* @return Returns a KTask handle.
*/
KTask* createTask(size_t stackSize, uint8_t priority, TaskFunc entry, void *taskArg);
/**
* @brief Switches to the next task. Use with care.
*/
void yieldTask(void);
/**
* @brief Task exit function. Must be called from the task that exits.
*/
void taskExit(void);
#ifdef __cplusplus
} // extern "C"
#endif

87
kernel/include/kevent.h Normal file
View File

@ -0,0 +1,87 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdbool.h>
#include "kernel.h"
#ifdef __cplusplus
extern "C"
{
#endif
typedef struct KEvent KEvent;
/**
* @brief Creates a new KEvent.
*
* @param[in] oneShot Event fires only once and auto clears if true.
*
* @return The KEvent pointer or NULL when out of memory.
*/
KEvent* createEvent(bool oneShot);
/**
* @brief Deletes a KEvent.
*
* @param[in] kevent The KEvent pointer.
*/
void deleteEvent(KEvent *const kevent);
/**
* @brief Binds the given KEvent to an interrupt.
*
* @param[in] kevent The KEvent pointer.
* @param[in] id The interrupt id.
* @param[in] prio The interrupt priority.
*/
void bindInterruptToEvent(KEvent *const kevent, uint8_t id, uint8_t prio);
void unbindInterruptEvent(uint8_t id);
/**
* @brief Waits for the given KEvent to be signaled.
*
* @param[in] kevent The KEvent pointer.
*
* @return Returns the result. See Kres above.
*/
KRes waitForEvent(KEvent *const kevent);
/**
* @brief Signals a KEvent.
*
* @param[in] kevent The KEvent pointer.
* @param[in] reschedule Set to true to immediately reschedule.
*/
void signalEvent(KEvent *const kevent, bool reschedule);
/**
* @brief Clears a KEvent.
*
* @param[in] kevent The KEvent pointer.
*/
void clearEvent(KEvent *const kevent);
#ifdef __cplusplus
} // extern "C"
#endif

68
kernel/include/kmutex.h Normal file
View File

@ -0,0 +1,68 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "kernel.h"
#ifdef __cplusplus
extern "C"
{
#endif
typedef struct KMutex KMutex; // TODO: Implement this using semaphores?
/**
* @brief Creates a new KMutex.
*
* @return The KMutex pointer or NULL when out of memory.
*/
KMutex* createMutex(void);
/**
* @brief Deletes a KMutex.
*
* @param[in] kmutex The KMutex pointer.
*/
void deleteMutex(KMutex *const kmutex);
/**
* @brief Locks a KMutex.
*
* @param[in] kmutex The KMutex pointer.
*
* @return Returns the result. See Kres.
*/
KRes lockMutex(KMutex *const kmutex);
/**
* @brief Unlocks a KMutex.
*
* @param[in] kmutex The KMutex pointer.
*
* @return Returns KRES_NO_PERMISSIONS if the current task
* @return is not the owner. Otherwise KRES_OK.
*/
KRes unlockMutex(KMutex *const kmutex);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -0,0 +1,80 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <stdbool.h>
#include "kernel.h"
#ifdef __cplusplus
extern "C"
{
#endif
typedef struct KSema KSema;
/**
* @brief Creates a new KSema.
*
* @param[in] count The initial count of the semaphore.
*
* @return The KSema pointer or NULL when out of memory.
*/
KSema* createSemaphore(int32_t count);
/**
* @brief Deletes a KSema.
*
* @param[in] ksema The KSema handle.
*/
void deleteSemaphore(KSema *const ksema);
/**
* @brief Polls a KSema.
*
* @param[in] ksema The KSema pointer.
*
* @return Returns KRES_OK or KRES_WOULD_BLOCK.
*/
KRes pollSemaphore(KSema *const ksema);
/**
* @brief Decreases the semaphore and blocks if <=0.
*
* @param[in] ksema The KSema pointer.
*
* @return Returns the result. See Kres above.
*/
KRes waitForSemaphore(KSema *const ksema);
/**
* @brief Increases the semaphore and wakes up signalCount waiting tasks if any.
*
* @param[in] ksema The KSema pointer.
* @param[in] signalCount The number to increase the semaphore by.
* @param[in] reschedule Set to true to immediately reschedule.
*/
void signalSemaphore(KSema *const ksema, uint32_t signalCount, bool reschedule);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -1,8 +1,8 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2023 profi200
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -18,9 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "types.h"
#include "arm11/config.h"
#include "kernel.h"
#ifdef __cplusplus
@ -28,18 +26,19 @@ extern "C"
{
#endif
typedef struct
{
u8 sha1[20];
char serial[4];
u32 attr;
} GbaDbEntry;
static_assert(sizeof(GbaDbEntry) == 28, "Error: GBA DB entry struct is not packed!");
typedef struct KTimer KTimer;
u16 detectSaveType(const u32 romSize, const u16 defaultSave);
u16 getSaveType(const OafConfig *const cfg, const u32 romSize, const char *const savePath);
KTimer* createTimer(bool pulse);
void deleteTimer(KTimer *const ktimer);
void startTimer(KTimer *const ktimer, uint32_t usec);
void stopTimer(KTimer *const ktimer);
KRes waitForTimer(KTimer *const ktimer);
#ifdef __cplusplus
} // extern "C"

View File

@ -0,0 +1,67 @@
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "asm_macros.h"
.arm
.cpu mpcore
.fpu vfpv2
@ void switchContextNoScratchRegs(u32 *curRegs, const u32 *newRegs)
/*ASM_FUNC switchContextNoScratchRegs
stmia r0!, {r4-r11, sp, lr}
add r0, r0, #20 @ Skip r0-r3, r12
adr r2, switchContextNoScratchRegs_end
mrs r3, cpsr
stmia r0, {r2, r3}
ldmia r1!, {r4-r11, sp, lr}
add r1, r1, #20 @ Skip r0-r3, r12
rfeia r1
switchContextNoScratchRegs_end:
cpsie i
bx lr
@ void switchContextAllRegs(u32 *curRegs, const u32 *newRegs)
ASM_FUNC switchContextAllRegs
stmia r0!, {r4-r11, sp, lr}
add r0, r0, #20 @ Skip r0-r3, r12
adr r2, switchContextAllRegs_end
mrs r3, cpsr
stmia r0, {r2, r3}
ldmia r1!, {r4-r11, sp, lr}
ldr r3, [r1, #24] @ cpsr
cps #19 @ SVC mode
msr spsr_fsxc, r3
ldmia r1, {r0-r3, r12, pc}^
switchContextAllRegs_end:
cpsie i
bx lr*/
@ KRes switchContext(KRes res, uintptr_t *oldSp, uintptr_t newSp);
BEGIN_ASM_FUNC switchContext
stmfd sp!, {r4-r11, lr}
str sp, [r1]
mov sp, r2
ldmfd sp!, {r4-r11, lr}
bx lr
END_ASM_FUNC
.pool

258
kernel/source/kernel.c Normal file
View File

@ -0,0 +1,258 @@
#include <stdlib.h>
#include <stdnoreturn.h>
#include <string.h>
#include "types.h"
#include "kernel.h"
#include "internal/config.h"
#include "internal/kernel_private.h"
#include "internal/kmemcpy_set.h"
#include "internal/slabheap.h"
#include "internal/util.h"
#include "internal/list.h"
#include "internal/contextswitch.h"
#include "arm.h"
static TaskCb *g_curTask = NULL;
static u32 g_readyBitmap = 0;
static ListNode g_runQueues[MAX_PRIO_BITS] = {0};
static SlabHeap g_taskSlab = {0};
static u32 g_numTasks = 0;
static TaskCb *g_curDeadTask = NULL; // TODO: Improve dead task handling.
static KRes scheduler(TaskState curTaskState);
noreturn static void kernelIdleTask(void);
static void initKernelState(void)
{
for(int i = 0; i < MAX_PRIO_BITS; i++) listInit(&g_runQueues[i]);
slabInit(&g_taskSlab, sizeof(TaskCb), MAX_TASKS);
_eventSlabInit();
_mutexSlabInit();
_semaphoreSlabInit();
//_timerInit();
}
/*
* Public kernel API.
*/
// TODO: Are KTask handles needed? (for the main task)
// TODO: Thread local storage. Needed?
void kernelInit(uint8_t priority)
{
if(priority > MAX_PRIO_BITS - 1u) return;
// TODO: Split this mess into helper functions.
initKernelState();
TaskCb *const idleT = (TaskCb*)slabAlloc(&g_taskSlab);
void *const iStack = malloc(IDLE_STACK_SIZE);
TaskCb *const mainT = (TaskCb*)slabCalloc(&g_taskSlab, sizeof(TaskCb));
if(idleT == NULL || iStack == NULL || mainT == NULL)
{
slabFree(&g_taskSlab, idleT);
free(iStack);
slabFree(&g_taskSlab, mainT);
return;
}
cpuRegs *const regs = (cpuRegs*)(iStack + IDLE_STACK_SIZE - sizeof(cpuRegs));
regs->lr = (u32)kernelIdleTask;
idleT->prio = 1;
// id is already set to 0.
idleT->savedSp = (uintptr_t)regs;
idleT->stack = iStack;
// Main task already running. Nothing more to setup.
mainT->id = 1;
mainT->prio = priority;
g_curTask = mainT;
g_readyBitmap = 1u<<1; // The idle task has priority 1 and is always ready.
listPush(&g_runQueues[1], &idleT->node);
g_numTasks = 2;
}
KTask* createTask(size_t stackSize, uint8_t priority, TaskFunc entry, void *taskArg)
{
if(priority > MAX_PRIO_BITS - 1u) return NULL;
// Make sure the stack is aligned to 8 bytes
stackSize = (stackSize + 7u) & ~7u;
SlabHeap *const taskSlabPtr = &g_taskSlab;
TaskCb *const newT = (TaskCb*)slabAlloc(taskSlabPtr);
void *const stack = malloc(stackSize);
if(newT == NULL || stack == NULL)
{
slabFree(taskSlabPtr, newT);
free(stack);
return NULL;
}
cpuRegs *const regs = (cpuRegs*)(stack + stackSize - sizeof(cpuRegs));
kmemset((u32*)regs, 0, sizeof(cpuRegs));
regs->lr = (u32)entry;
newT->prio = priority;
newT->id = g_numTasks; // TODO: Make this more sophisticated.
// TODO: This is kinda hacky abusing the result member to pass the task arg.
// Pass args and stuff on the stack?
newT->res = (KRes)taskArg;
newT->savedSp = (uintptr_t)regs;
newT->stack = stack;
kernelLock();
listPush(&g_runQueues[priority], &newT->node);
g_readyBitmap |= 1u<<priority;
g_numTasks++;
kernelUnlock();
return newT;
}
// TODO: setTaskPriority().
void yieldTask(void)
{
kernelLock();
scheduler(TASK_STATE_RUNNING);
}
void taskExit(void)
{
kernelLock();
scheduler(TASK_STATE_DEAD);
while(1); // TODO: panic?
}
/*
* Internal functions.
*/
const TaskCb* getCurrentTask(void)
{
return g_curTask;
}
// The wait queue and scheduler functions automatically unlock the kernel lock
// and expect to be called with locked lock.
KRes waitQueueBlock(ListNode *waitQueue)
{
listPush(waitQueue, &g_curTask->node);
return scheduler(TASK_STATE_BLOCKED);
}
bool waitQueueWakeN(ListNode *waitQueue, u32 wakeCount, KRes res, bool reschedule)
{
if(listEmpty(waitQueue) || !wakeCount)
{
kernelUnlock();
return false;
}
u32 readyBitmap = 0;
ListNode *const runQueues = g_runQueues;
if(LIKELY(reschedule))
{
// Put ourself on top of the list first so we run immediately
// after the woken tasks to finish the work we were doing.
// TODO: Verify if this is a good strategy.
TaskCb *const curTask = g_curTask;
const u8 curPrio = curTask->prio;
listPushTail(&runQueues[curPrio], &curTask->node);
readyBitmap = 1u<<curPrio;
}
do
{
/*
* Edge case:
* 2 tasks, 1 single shot event. Task 2 waits first and then task 1.
* When signaled (by an IRQ) only task 1 will ever run instead of
* alternating between both because task 1 always lands on the
* head (as intended) but on wakeup we take N tasks from the head
* to preserve order.
*
* Workaround:
* Take tasks from the tail instead. This will however punish
* the longest waiting tasks unnecessarily.
*/
//TaskCb *task = LIST_ENTRY(listPopHead(waitQueue), TaskCb, node);
TaskCb *task = LIST_ENTRY(listPop(waitQueue), TaskCb, node);
readyBitmap |= 1u<<task->prio;
task->res = res;
listPushTail(&runQueues[task->prio], &task->node);
} while(!listEmpty(waitQueue) && --wakeCount);
g_readyBitmap |= readyBitmap;
if(LIKELY(reschedule)) scheduler(TASK_STATE_RUNNING_SHORT);
else kernelUnlock();
return true;
}
static KRes scheduler(TaskState curTaskState)
{
#ifndef NDEBUG
if((__getCpsr() & PSR_MODE_MASK) != PSR_SYS_MODE) panic();
#endif
TaskCb *const curDeadTask = g_curDeadTask;
// TODO: Get rid of this and find a better way.
if(UNLIKELY(curDeadTask != NULL))
{
free(curDeadTask->stack);
slabFree(&g_taskSlab, curDeadTask);
g_curDeadTask = NULL;
}
TaskCb *const curTask = g_curTask;
u32 readyBitmap = g_readyBitmap;
ListNode *const runQueues = g_runQueues;
// Warning. The result is undefined if the input of this builtin is 0!
// Edge case: All tasks are sleeping except the (curently running) idle task.
// g_readyBitmap is 0 in this case.
const unsigned int readyPrio = (readyBitmap ? 31u - __builtin_clz(readyBitmap) : 0u);
if(LIKELY(curTaskState == TASK_STATE_RUNNING))
{
const u8 curPrio = curTask->prio;
if(readyPrio < curPrio)
{
kernelUnlock();
return KRES_OK;
}
listPush(&runQueues[curPrio], &curTask->node);
readyBitmap |= 1u<<curPrio;
}
else if(UNLIKELY(curTaskState == TASK_STATE_DEAD))
{
g_curDeadTask = curTask;
g_numTasks--;
}
TaskCb *newTask = LIST_ENTRY(listPop(&runQueues[readyPrio]), TaskCb, node);
if(listEmpty(&runQueues[readyPrio])) readyBitmap &= ~(1u<<readyPrio);
g_readyBitmap = readyBitmap;
TaskCb *oldTask = curTask;
g_curTask = newTask;
const KRes res = newTask->res;
kernelUnlock();
return switchContext(res, &oldTask->savedSp, newTask->savedSp);
}
// TODO: Cleanup deleted tasks in here? Or create a worker task?
noreturn static void kernelIdleTask(void)
{
do
{
__wfi();
kernelLock();
scheduler(TASK_STATE_RUNNING);
} while(1);
}

112
kernel/source/kevent.c Normal file
View File

@ -0,0 +1,112 @@
#include <stdbool.h>
#include <stdlib.h>
#include "types.h"
#include "kevent.h"
#include "internal/list.h"
#include "arm11/hardware/interrupt.h"
#include "internal/kernel_private.h"
#include "internal/slabheap.h"
#include "internal/config.h"
struct KEvent
{
bool signaled;
const bool oneShot;
ListNode waitQueue;
};
static SlabHeap g_eventSlab = {0};
static KEvent *g_irqEventTable[128 - 32] = {0}; // 128 - 32 private interrupts.
void _eventSlabInit(void)
{
slabInit(&g_eventSlab, sizeof(KEvent), MAX_EVENTS);
}
static void eventIrqHandler(u32 intSource)
{
signalEvent(g_irqEventTable[intSource - 32], false);
}
KEvent* createEvent(bool oneShot)
{
KEvent *const kevent = (KEvent*)slabAlloc(&g_eventSlab);
kevent->signaled = false;
*(bool*)&kevent->oneShot = oneShot;
listInit(&kevent->waitQueue);
return kevent;
}
void deleteEvent(KEvent *const kevent)
{
kernelLock();
waitQueueWakeN(&kevent->waitQueue, (u32)-1, KRES_HANDLE_DELETED, true);
slabFree(&g_eventSlab, kevent);
}
// TODO: Critical sections needed for bind/unbind?
void bindInterruptToEvent(KEvent *const kevent, uint8_t id, uint8_t prio)
{
if(id < 32 || id > 127) return;
g_irqEventTable[id - 32] = kevent;
IRQ_registerIsr(id, prio, 0, eventIrqHandler);
}
void unbindInterruptEvent(uint8_t id)
{
if(id < 32 || id > 127) return;
g_irqEventTable[id - 32] = NULL;
IRQ_unregisterIsr(id);
}
// TODO: Timeout.
KRes waitForEvent(KEvent *const kevent)
{
KRes res;
kernelLock();
if(kevent->signaled)
{
if(kevent->oneShot) kevent->signaled = false;
kernelUnlock();
res = KRES_OK;
}
else res = waitQueueBlock(&kevent->waitQueue);
return res;
}
void signalEvent(KEvent *const kevent, bool reschedule)
{
kernelLock();
if(!kevent->signaled)
{
if(kevent->oneShot)
{
if(!waitQueueWakeN(&kevent->waitQueue, 1, KRES_OK, reschedule))
kevent->signaled = true;
}
else
{
kevent->signaled = true;
waitQueueWakeN(&kevent->waitQueue, (u32)-1, KRES_OK, reschedule);
}
}
else kernelUnlock();
}
void clearEvent(KEvent *const kevent)
{
kernelLock(); // TODO: Can we do this without locks?
kevent->signaled = false;
kernelUnlock();
}

101
kernel/source/kmemcpy_set.s Normal file
View File

@ -0,0 +1,101 @@
/*
* This file is part of fastboot 3DS
* Copyright (C) 2019 Aurora Wright, TuxSH, derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@ Based on https://github.com/AuroraWright/Luma3DS/blob/master/arm9/source/alignedseqmemcpy.s
.arm
.cpu arm946e-s
.fpu softvfp
@ void kmemcpy(u32 *restrict dst, const u32 *restrict src, u32 size);
@ void iokmemcpy(vu32 *restrict dst, const vu32 *restrict src, u32 size);
.section .text.kmemcpy, "ax", %progbits
.global kmemcpy
.global iokmemcpy
.type kmemcpy %function
.type iokmemcpy %function
.align 2
kmemcpy:
iokmemcpy:
bics r12, r2, #31
beq kmemcpy_test_words
stmfd sp!, {r4-r10}
kmemcpy_blocks_lp:
ldmia r1!, {r3-r10}
subs r12, #32
stmia r0!, {r3-r10}
bne kmemcpy_blocks_lp
ldmfd sp!, {r4-r10}
kmemcpy_test_words:
ands r12, r2, #28
beq kmemcpy_halfword_byte
kmemcpy_words_lp:
ldr r3, [r1], #4
subs r12, #4
str r3, [r0], #4
bne kmemcpy_words_lp
kmemcpy_halfword_byte:
tst r2, #2
ldrneh r3, [r1], #2
strneh r3, [r0], #2
tst r2, #1
ldrneb r3, [r1]
strneb r3, [r0]
bx lr
@ void kmemset(u32 *ptr, u32 value, u32 size);
@ void iokmemset(vu32 *ptr, u32 value, u32 size);
.section .text.kmemset, "ax", %progbits
.global kmemset
.global iokmemset
.type kmemset %function
.type iokmemset %function
.align 2
kmemset:
iokmemset:
bics r12, r2, #31
beq kmemset_test_words
stmfd sp!, {r4-r9}
mov r3, r1
mov r4, r1
mov r5, r1
mov r6, r1
mov r7, r1
mov r8, r1
mov r9, r1
kmemset_blocks_lp:
stmia r0!, {r1, r3-r9}
subs r12, #32
bne kmemset_blocks_lp
ldmfd sp!, {r4-r9}
kmemset_test_words:
ands r12, r2, #28
beq kmemset_halfword_byte
kmemset_words_lp:
str r1, [r0], #4
subs r12, #4
bne kmemset_words_lp
kmemset_halfword_byte:
tst r2, #2
strneh r1, [r0], #2
tst r2, #1
strneb r1, [r0]
bx lr

88
kernel/source/kmutex.c Normal file
View File

@ -0,0 +1,88 @@
#include <stdlib.h>
#include "types.h"
#include "kmutex.h"
#include "internal/list.h"
#include "internal/kernel_private.h"
#include "internal/util.h"
#include "internal/slabheap.h"
#include "internal/config.h"
struct KMutex
{
const TaskCb *owner;
ListNode waitQueue;
};
static SlabHeap g_mutexSlab = {0};
void _mutexSlabInit(void)
{
slabInit(&g_mutexSlab, sizeof(KMutex), MAX_MUTEXES);
}
// TODO: Test mutex with multiple cores.
KMutex* createMutex(void)
{
KMutex *const kmutex = (KMutex*)slabAlloc(&g_mutexSlab);
kmutex->owner = NULL;
listInit(&kmutex->waitQueue);
return kmutex;
}
void deleteMutex(KMutex *const kmutex)
{
kernelLock();
waitQueueWakeN(&kmutex->waitQueue, (u32)-1, KRES_HANDLE_DELETED, true);
slabFree(&g_mutexSlab, kmutex);
}
KRes lockMutex(KMutex *const kmutex)
{
KRes res;
do
{
kernelLock();
if(UNLIKELY(kmutex->owner != NULL))
{
res = waitQueueBlock(&kmutex->waitQueue);
if(UNLIKELY(res != KRES_OK)) break;
}
else
{
kmutex->owner = getCurrentTask();
kernelUnlock();
res = KRES_OK;
break;
}
} while(1);
return res;
}
// TODO: Test if it works and only unlocks if current task == owner.
KRes unlockMutex(KMutex *const kmutex)
{
KRes res = KRES_OK;
kernelLock();
if(LIKELY(kmutex->owner != NULL))
{
if(LIKELY(kmutex->owner == getCurrentTask()))
{
kmutex->owner = NULL;
waitQueueWakeN(&kmutex->waitQueue, 1, KRES_OK, true);
}
else res = KRES_NO_PERMISSIONS;
}
else kernelUnlock();
return res;
}

View File

@ -0,0 +1,78 @@
#include <stdbool.h>
#include <stdlib.h>
#include "types.h"
#include "ksemaphore.h"
#include "internal/list.h"
#include "internal/kernel_private.h"
#include "internal/util.h"
#include "internal/slabheap.h"
#include "internal/config.h"
struct KSema
{
s32 count;
ListNode waitQueue;
};
static SlabHeap g_semaSlab = {0};
void _semaphoreSlabInit(void)
{
slabInit(&g_semaSlab, sizeof(KSema), MAX_SEMAPHORES);
}
// TODO: Test semaphore with multiple cores.
KSema* createSemaphore(int32_t count)
{
KSema *const ksema = (KSema*)slabAlloc(&g_semaSlab);
ksema->count = count;
listInit(&ksema->waitQueue);
return ksema;
}
void deleteSemaphore(KSema *const ksema)
{
kernelLock();
waitQueueWakeN(&ksema->waitQueue, (u32)-1, KRES_HANDLE_DELETED, true);
slabFree(&g_semaSlab, ksema);
}
KRes pollSemaphore(KSema *const ksema)
{
KRes res;
// TODO: Plain spinlocks instead?
kernelLock();
if(UNLIKELY(ksema->count <= 0)) res = KRES_WOULD_BLOCK;
else {ksema->count--; res = KRES_OK;}
kernelUnlock();
return res;
}
KRes waitForSemaphore(KSema *const ksema)
{
KRes res;
kernelLock();
if(UNLIKELY(--ksema->count < 0)) res = waitQueueBlock(&ksema->waitQueue);
else {kernelUnlock(); res = KRES_OK;}
return res;
}
void signalSemaphore(KSema *const ksema, uint32_t signalCount, bool reschedule)
{
kernelLock();
//if(UNLIKELY(++ksema->count <= 0))
if(UNLIKELY((ksema->count += signalCount) <= 0))
waitQueueWakeN(&ksema->waitQueue, signalCount, KRES_OK, reschedule);
else kernelUnlock();
}

110
kernel/source/ktimer.c Normal file
View File

@ -0,0 +1,110 @@
#include <stdbool.h>
#include <stdlib.h>
#include "types.h"
#include "ktimer.h"
#include "internal/list.h"
#include "arm11/hardware/interrupt.h"
#include "arm11/hardware/timer.h"
#include "internal/kernel_private.h"
#include "internal/slabheap.h"
#include "internal/config.h"
//#include "arm11/fmt.h"
/*struct KTimer
{
ListNode node;
u32 delta;
u32 ticks;
const bool pulse;
ListNode waitQueue;
};
static SlabHeap g_timerSlab = {0};
static ListNode g_deltaQueue = {0};
static void timerIsr(UNUSED u32 intSource);
static void addToDeltaQueue(KTimer *const timer, u32 ticks);
void _timerInit(void)
{
slabInit(&g_timerSlab, sizeof(KTimer), MAX_TIMERS);
listInit(&g_deltaQueue);
IRQ_registerIsr(IRQ_TIMER, 12, 0, timerIsr);
}
KTimer* createTimer(bool pulse)
{
KTimer *const ktimer = (KTimer*)slabAlloc(&g_timerSlab);
*(bool*)&ktimer->pulse = pulse;
listInit(&ktimer->waitQueue);
return ktimer;
}
void deleteTimer(KTimer *const ktimer)
{
kernelLock();
waitQueueWakeN(&ktimer->waitQueue, (u32)-1, KRES_HANDLE_DELETED, true);
slabFree(&g_timerSlab, ktimer);
}
static void timerIsr(UNUSED u32 intSource)
{
kernelLock();
//if(listEmpty(&g_deltaQueue)) *((vu32*)4) = 4; // This should never happen
KTimer *ktimer = LIST_ENTRY(listPop(&g_deltaQueue), KTimer, node);
if(ktimer->pulse) addToDeltaQueue(ktimer, ktimer->ticks);
if(!listEmpty(&g_deltaQueue))
{
// Don't use fp math in ISRs.
TIMER_start(1, LIST_FIRST_ENTRY(&g_deltaQueue, KTimer, node)->delta, false, true);
}
waitQueueWakeN(&ktimer->waitQueue, (u32)-1, KRES_OK, false);
}
static void addToDeltaQueue(KTimer *const ktimer, u32 ticks)
{
KTimer *pos;
u32 deltaSum = 0;
LIST_FOR_EACH_ENTRY(pos, &g_deltaQueue, node)
{
deltaSum += pos->delta;
if(deltaSum > ticks)
{
ktimer->delta = ticks - (deltaSum - pos->delta);
listAddBefore(&pos->node, &ktimer->node);
return;
}
}
ktimer->delta = ticks;
listPush(&g_deltaQueue, &ktimer->node);
}
void startTimer(KTimer *const ktimer, uint32_t usec)
{
const u32 ticks = TIMER_FREQ(1, 1000000) * usec;
ktimer->ticks = ticks;
kernelLock();
const bool firstTimer = listEmpty(&g_deltaQueue);
addToDeltaQueue(ktimer, ticks);
kernelUnlock();
if(firstTimer) TIMER_start(1, ticks, false, true);
}
void stopTimer(KTimer *const ktimer)
{
}
KRes waitForTimer(KTimer *const ktimer)
{
kernelLock();
return waitQueueBlock(&ktimer->waitQueue);
}*/

44
kernel/source/slabheap.c Normal file
View File

@ -0,0 +1,44 @@
#include <stddef.h>
#include <stdlib.h>
#include "internal/slabheap.h"
#include "internal/kmemcpy_set.h"
void slabInit(SlabHeap *slab, size_t objSize, size_t num)
{
if(objSize < sizeof(SlabHeap) || !num) return;
listInit(slab);
void *pool = malloc(objSize * num);
if(!pool) return;
do
{
listPush(slab, (SlabHeap*)pool);
pool += objSize;
} while(--num);
}
void* slabAlloc(SlabHeap *slab)
{
if(!slab || listEmpty(slab)) return NULL;
return listPop(slab);
}
void* slabCalloc(SlabHeap *slab, size_t clrSize)
{
void *const ptr = slabAlloc(slab);
if(ptr) kmemset(ptr, 0, clrSize);
return ptr;
}
void slabFree(SlabHeap *slab, void *ptr)
{
if(!slab || !ptr) return;
// Keep gaps filled by allocating the same mem
// again next time an object is allocated.
listPushTail(slab, (SlabHeap*)ptr);
}

@ -1 +0,0 @@
Subproject commit ed4525140dacc54e5924f60b25a00c69371866a0

@ -1 +0,0 @@
Subproject commit f6717f66858634b677ed695ee346a89db7684b43

Binary file not shown.

View File

@ -0,0 +1,48 @@
#pragma once
static rbtree_t sAddrMap;
struct addrMapNode
{
rbtree_node node;
MemChunk chunk;
};
#define getAddrMapNode(x) rbtree_item((x), addrMapNode, node)
static int addrMapNodeComparator(const rbtree_node_t* _lhs, const rbtree_node_t* _rhs)
{
auto lhs = getAddrMapNode(_lhs)->chunk.addr;
auto rhs = getAddrMapNode(_rhs)->chunk.addr;
if (lhs < rhs)
return -1;
if (lhs > rhs)
return 1;
return 0;
}
static void addrMapNodeDestructor(rbtree_node_t* a)
{
free(getAddrMapNode(a));
}
static addrMapNode* getNode(void* addr)
{
addrMapNode n;
n.chunk.addr = (u8*)addr;
auto p = rbtree_find(&sAddrMap, &n.node);
return p ? getAddrMapNode(p) : nullptr;
}
static addrMapNode* newNode(const MemChunk& chunk)
{
auto p = (addrMapNode*)malloc(sizeof(addrMapNode));
if (!p) return nullptr;
p->chunk = chunk;
return p;
}
static void delNode(addrMapNode* node)
{
rbtree_remove(&sAddrMap, &node->node, addrMapNodeDestructor);
}

View File

@ -0,0 +1,154 @@
#include "mem_pool.h"
/*
// This method is currently unused
void MemPool::CoalesceLeft(MemBlock* b)
{
auto curPtr = b->base;
for (auto p = b->prev; p; p = p->prev)
{
if ((p->base + p->size) != curPtr) break;
curPtr = p->base;
p->size += b->size;
DelBlock(b);
b = p;
}
}
*/
void MemPool::CoalesceRight(MemBlock* b)
{
auto curPtr = b->base + b->size;
auto next = b->next;
for (auto n = next; n; n = next)
{
next = n->next;
if (n->base != curPtr) break;
b->size += n->size;
curPtr += n->size;
DelBlock(n);
}
}
bool MemPool::Allocate(MemChunk& chunk, u32 size, int align)
{
// Don't shift out of bounds (CERT INT34-C)
if(align >= 32 || align < 0)
return false;
// Alignment must not be 0
if(align == 0)
return false;
u32 alignMask = (1 << align) - 1;
// Check if size doesn't fit neatly in alignment
if(size & alignMask)
{
// Make sure addition won't overflow (CERT INT30-C)
if(size > UINT32_MAX - alignMask)
return false;
// Pad size to next alignment
size = (size + alignMask) &~ alignMask;
}
// Find the first suitable block
for (auto b = first; b; b = b->next)
{
auto addr = b->base;
u32 begWaste = (u32)addr & alignMask;
if (begWaste > 0) begWaste = alignMask + 1 - begWaste;
if (begWaste > b->size) continue;
addr += begWaste;
u32 bSize = b->size - begWaste;
if (bSize < size) continue;
// Found space!
chunk.addr = addr;
chunk.size = size;
// Resize the block
if (!begWaste)
{
b->base += size;
b->size -= size;
if (!b->size)
DelBlock(b);
} else
{
auto nAddr = addr + size;
auto nSize = bSize - size;
b->size = begWaste;
if (nSize)
{
// We need to add the tail chunk that wasn't used to the list
auto n = MemBlock::Create(nAddr, nSize);
if (n) InsertAfter(b, n);
else chunk.size += nSize; // we have no choice but to waste the space.
}
}
return true;
}
return false;
}
void MemPool::Deallocate(const MemChunk& chunk)
{
u8* cAddr = chunk.addr;
auto cSize = chunk.size;
bool done = false;
// Try to merge the chunk somewhere into the list
for (auto b = first; !done && b; b = b->next)
{
auto addr = b->base;
if (addr > cAddr)
{
if ((cAddr + cSize) == addr)
{
// Merge the chunk to the left of the block
b->base = cAddr;
b->size += cSize;
} else
{
// We need to insert a new block
auto c = MemBlock::Create(cAddr, cSize);
if (c) InsertBefore(b, c);
}
done = true;
} else if ((b->base + b->size) == cAddr)
{
// Coalesce to the right
b->size += cSize;
CoalesceRight(b);
done = true;
}
}
if (!done)
{
// Either the list is empty or the chunk address is past the end
// address of the last block -- let's add a new block at the end
auto b = MemBlock::Create(cAddr, cSize);
if (b) AddBlock(b);
}
}
/*
void MemPool::Dump(const char* title)
{
printf("<%s> VRAM Pool Dump\n", title);
for (auto b = first; b; b = b->next)
printf(" - %p (%u bytes)\n", b->base, b->size);
}
*/
u32 MemPool::GetFreeSpace()
{
u32 acc = 0;
for (auto b = first; b; b = b->next)
acc += b->size;
return acc;
}

View File

@ -0,0 +1,90 @@
#pragma once
#include "types.h"
#include <stdlib.h>
struct MemChunk
{
u8* addr;
u32 size;
};
struct MemBlock
{
MemBlock *prev, *next;
u8* base;
u32 size;
static MemBlock* Create(u8* base, u32 size)
{
auto b = (MemBlock*)malloc(sizeof(MemBlock));
if (!b) return nullptr;
b->prev = nullptr;
b->next = nullptr;
b->base = base;
b->size = size;
return b;
}
};
struct MemPool
{
MemBlock *first, *last;
bool Ready() { return first != nullptr; }
void AddBlock(MemBlock* blk)
{
blk->prev = last;
if (last) last->next = blk;
if (!first) first = blk;
last = blk;
}
void DelBlock(MemBlock* b)
{
auto prev = b->prev, &pNext = prev ? prev->next : first;
auto next = b->next, &nPrev = next ? next->prev : last;
pNext = next;
nPrev = prev;
free(b);
}
void InsertBefore(MemBlock* b, MemBlock* p)
{
auto prev = b->prev, &pNext = prev ? prev->next : first;
b->prev = p;
p->next = b;
p->prev = prev;
pNext = p;
}
void InsertAfter(MemBlock* b, MemBlock* n)
{
auto next = b->next, &nPrev = next ? next->prev : last;
b->next = n;
n->prev = b;
n->next = next;
nPrev = n;
}
//void CoalesceLeft(MemBlock* b);
void CoalesceRight(MemBlock* b);
bool Allocate(MemChunk& chunk, u32 size, int align);
void Deallocate(const MemChunk& chunk);
void Destroy()
{
MemBlock* next = nullptr;
for (auto b = first; b; b = next)
{
next = b->next;
free(b);
}
first = nullptr;
last = nullptr;
}
//void Dump(const char* title);
u32 GetFreeSpace();
};

View File

@ -0,0 +1,95 @@
extern "C"
{
#include "types.h"
#include "arm11/allocator/vram.h"
#include "arm11/util/rbtree.h"
}
#include "mem_pool.h"
#include "addrmap.h"
static MemPool sVramPool;
static bool vramInit()
{
auto blk = MemBlock::Create((u8*)0x18000000, 0x00600000);
if (blk)
{
sVramPool.AddBlock(blk);
rbtree_init(&sAddrMap, addrMapNodeComparator);
return true;
}
return false;
}
void* vramMemAlign(size_t size, size_t alignment)
{
// Enforce minimum alignment
if (alignment < 16)
alignment = 16;
// Convert alignment to shift amount
int shift;
for (shift = 4; shift < 32; shift ++)
{
if ((1U<<shift) == alignment)
break;
}
if (shift == 32) // Invalid alignment
return nullptr;
// Initialize the pool if it is not ready
if (!sVramPool.Ready() && !vramInit())
return nullptr;
// Allocate the chunk
MemChunk chunk;
if (!sVramPool.Allocate(chunk, size, shift))
return nullptr;
auto node = newNode(chunk);
if (!node)
{
sVramPool.Deallocate(chunk);
return nullptr;
}
if (rbtree_insert(&sAddrMap, &node->node)) {}
return chunk.addr;
}
void* vramAlloc(size_t size)
{
return vramMemAlign(size, 0x80);
}
void* vramRealloc(void* mem, size_t size)
{
(void)mem;
(void)size;
// TODO
return NULL;
}
size_t vramGetSize(void* mem)
{
auto node = getNode(mem);
return node ? node->chunk.size : 0;
}
void vramFree(void* mem)
{
auto node = getNode(mem);
if (!node) return;
// Free the chunk
sVramPool.Deallocate(node->chunk);
// Free the node
delNode(node);
}
u32 vramSpaceFree()
{
return sVramPool.GetFreeSpace();
}

View File

@ -1,323 +0,0 @@
/*
* This file is part of open_agb_firm
* Copyright (C) 2024 profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include "types.h"
#include "arm11/config.h"
#include "inih/ini.h"
#include "util.h"
#include "fsutil.h"
#define INI_BUF_SIZE (1024u)
#define DEFAULT_CONFIG "[general]\n" \
"backlight=64\n" \
"backlightSteps=5\n" \
"directBoot=false\n" \
"useGbaDb=true\n" \
"useSavesFolder=true\n\n" \
\
"[video]\n" \
"scaler=matrix\n" \
"colorProfile=none\n" \
"contrast=1.0\n" \
"brightness=0.0\n" \
"saturation=1.0\n\n" \
\
"[audio]\n" \
"audioOut=auto\n" \
"volume=127\n\n" \
\
"[advanced]\n" \
"saveOverride=false\n" \
"defaultSave=sram_256k"
// Default config.
OafConfig g_oafConfig =
{
// [general]
64, // backlight
5, // backlightSteps
false, // directBoot
true, // useGbaDb
true, // useSavesFolder
// [video]
2, // scaler
0, // colorProfile
1.f, // contrast
0.f, // brightness
1.f, // saturation
// [audio]
0, // Automatic audio output.
127, // Control via volume slider.
// [input]
{ // buttonMaps
0, // A
0, // B
0, // Select
0, // Start
0, // Right
0, // Left
0, // Up
0, // Down
0, // R
0 // L
},
// [game]
0, // saveSlot
255, // saveType
// [advanced]
false, // saveOverride
14 // defaultSave
};
static u32 parseButtons(const char *str)
{
if(str == NULL || *str == '\0') return 0;
char buf[32]; // Should be enough for all useful mappings.
buf[31] = '\0';
strncpy(buf, str, 31);
char *bufPtr = buf;
static const char *const buttonStrLut[32] =
{
"A", "B", "SELECT", "START", "RIGHT", "LEFT", "UP", "DOWN",
"R", "L", "X", "Y", "", "", "ZL", "ZR",
"", "", "", "", "TOUCH", "", "", "",
"CS_RIGHT", "CS_LEFT", "CS_UP", "CS_DOWN", "CP_RIGHT", "CP_LEFT", "CP_UP", "CP_DOWN"
};
u32 map = 0;
while(1)
{
char *const nextDelimiter = strchr(bufPtr, ',');
if(nextDelimiter != NULL) *nextDelimiter = '\0';
unsigned i = 0;
while(i < 32 && strcmp(buttonStrLut[i], bufPtr) != 0) ++i;
if(i == 32) break;
map |= 1u<<i;
if(nextDelimiter == NULL) break;
bufPtr = nextDelimiter + 1; // Skip delimiter.
}
// Empty strings will match the entry for bit 12.
return map & ~(1u<<12);
}
static int cfgIniCallback(void *user, const char *section, const char *name, const char *value)
{
OafConfig *const config = (OafConfig*)user;
if(strcmp(section, "general") == 0)
{
if(strcmp(name, "backlight") == 0)
config->backlight = (u8)strtoul(value, NULL, 10);
else if(strcmp(name, "backlightSteps") == 0)
config->backlightSteps = (u8)strtoul(value, NULL, 10);
else if(strcmp(name, "directBoot") == 0)
config->directBoot = (strcmp(value, "false") == 0 ? false : true);
else if(strcmp(name, "useGbaDb") == 0)
config->useGbaDb = (strcmp(value, "true") == 0 ? true : false);
else if(strcmp(name, "useSavesFolder") == 0)
config->useSavesFolder = (strcmp(value, "true") == 0 ? true : false);
}
else if(strcmp(section, "video") == 0)
{
if(strcmp(name, "scaler") == 0)
{
if(strcmp(value, "none") == 0)
config->scaler = 0;
else if(strcmp(value, "bilinear") == 0)
config->scaler = 1;
else if(strcmp(value, "matrix") == 0)
config->scaler = 2;
}
else if(strcmp(name, "colorProfile") == 0)
{
if(strcmp(value, "none") == 0)
config->colorProfile = 0;
else if(strcmp(value, "gba") == 0)
config->colorProfile = 1;
else if(strcmp(value, "gb_micro") == 0)
config->colorProfile = 2;
else if(strcmp(value, "gba_sp101") == 0)
config->colorProfile = 3;
else if(strcmp(value, "nds") == 0)
config->colorProfile = 4;
else if(strcmp(value, "ds_lite") == 0)
config->colorProfile = 5;
else if(strcmp(value, "nso") == 0)
config->colorProfile = 6;
else if(strcmp(value, "vba") == 0)
config->colorProfile = 7;
else if(strcmp(value, "identity") == 0)
config->colorProfile = 8;
//else if(strcmp(value, "custom") == 0) // TODO: Implement user provided profile.
// config->colorProfile = 9;
}
else if(strcmp(name, "contrast") == 0)
config->contrast = str2float(value);
else if(strcmp(name, "brightness") == 0)
config->brightness = str2float(value);
else if(strcmp(name, "saturation") == 0)
config->saturation = str2float(value);
}
else if(strcmp(section, "audio") == 0)
{
if(strcmp(name, "audioOut") == 0)
{
if(strcmp(value, "auto") == 0)
config->audioOut = 0;
else if(strcmp(value, "speakers") == 0)
config->audioOut = 1;
else if(strcmp(value, "headphones") == 0)
config->audioOut = 2;
}
else if(strcmp(name, "volume") == 0)
config->volume = (s8)strtol(value, NULL, 10);
}
else if(strcmp(section, "input") == 0)
{
const u32 button = parseButtons(name) & 0x3FFu; // Only allow GBA buttons.
if(button != 0)
{
// If the config option happens to abuse parseButtons() we will only use the highest bit.
const u32 shift = 31u - __builtin_clzl(button);
const u32 map = parseButtons(value);
config->buttonMaps[shift] = map;
}
}
else if(strcmp(section, "game") == 0)
{
if(strcmp(name, "saveSlot") == 0)
config->saveSlot = (u8)strtoul(value, NULL, 10);
if(strcmp(name, "saveType") == 0)
{
if(strcmp(value, "eeprom_8k") == 0)
config->saveType = 0;
if(strcmp(value, "rom_256m_eeprom_8k") == 0)
config->saveType = 1;
if(strcmp(value, "eeprom_64k") == 0)
config->saveType = 2;
if(strcmp(value, "rom_256m_eeprom_64k") == 0)
config->saveType = 3;
if(strcmp(value, "flash_512k_atmel_rtc") == 0)
config->saveType = 4;
if(strcmp(value, "flash_512k_atmel") == 0)
config->saveType = 5;
if(strcmp(value, "flash_512k_sst_rtc") == 0)
config->saveType = 6;
if(strcmp(value, "flash_512k_sst") == 0)
config->saveType = 7;
if(strcmp(value, "flash_512k_panasonic_rtc") == 0)
config->saveType = 8;
if(strcmp(value, "flash_512k_panasonic") == 0)
config->saveType = 9;
if(strcmp(value, "flash_1m_macronix_rtc") == 0)
config->saveType = 10;
if(strcmp(value, "flash_1m_macronix") == 0)
config->saveType = 11;
if(strcmp(value, "flash_1m_sanyo_rtc") == 0)
config->saveType = 12;
if(strcmp(value, "flash_1m_sanyo") == 0)
config->saveType = 13;
if(strcmp(value, "sram_256k") == 0)
config->saveType = 14;
if(strcmp(value, "none") == 0)
config->saveType = 15;
if(strcmp(value, "auto") == 0)
config->saveType = 255;
}
}
else if(strcmp(section, "advanced") == 0)
{
if(strcmp(name, "saveOverride") == 0)
config->saveOverride = (strcmp(value, "false") == 0 ? false : true);
if(strcmp(name, "defaultSave") == 0)
{
if(strcmp(value, "eeprom_8k") == 0)
config->defaultSave = 0;
if(strcmp(value, "rom_256m_eeprom_8k") == 0)
config->defaultSave = 1;
if(strcmp(value, "eeprom_64k") == 0)
config->defaultSave = 2;
if(strcmp(value, "rom_256m_eeprom_64k") == 0)
config->defaultSave = 3;
if(strcmp(value, "flash_512k_atmel_rtc") == 0)
config->defaultSave = 4;
if(strcmp(value, "flash_512k_atmel") == 0)
config->defaultSave = 5;
if(strcmp(value, "flash_512k_sst_rtc") == 0)
config->defaultSave = 6;
if(strcmp(value, "flash_512k_sst") == 0)
config->defaultSave = 7;
if(strcmp(value, "flash_512k_panasonic_rtc") == 0)
config->defaultSave = 8;
if(strcmp(value, "flash_512k_panasonic") == 0)
config->defaultSave = 9;
if(strcmp(value, "flash_1m_macronix_rtc") == 0)
config->defaultSave = 10;
if(strcmp(value, "flash_1m_macronix") == 0)
config->defaultSave = 11;
if(strcmp(value, "flash_1m_sanyo_rtc") == 0)
config->defaultSave = 12;
if(strcmp(value, "flash_1m_sanyo") == 0)
config->defaultSave = 13;
if(strcmp(value, "sram_256k") == 0)
config->defaultSave = 14;
if(strcmp(value, "none") == 0)
config->defaultSave = 15;
}
}
else return 0; // Error.
return 1; // 1 is no error? Really?
}
// TODO: Instead of writing a hardcoded string turn default config into a string.
Result parseOafConfig(const char *const path, OafConfig *cfg, const bool newCfgOnError)
{
char *iniBuf = (char*)calloc(INI_BUF_SIZE, 1);
if(iniBuf == NULL) return RES_OUT_OF_MEM;
cfg = (cfg != NULL ? cfg : &g_oafConfig);
Result res = fsQuickRead(path, iniBuf, INI_BUF_SIZE - 1);
if(res == RES_OK) ini_parse_string(iniBuf, cfgIniCallback, cfg);
else if(newCfgOnError)
{
const char *const defaultConfig = DEFAULT_CONFIG;
res = fsQuickWrite(path, defaultConfig, strlen(defaultConfig));
}
free(iniBuf);
return res;
}

800
source/arm11/console.c Normal file
View File

@ -0,0 +1,800 @@
/*
* This code is part of ctrulib (https://github.com/smealum/ctrulib)
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "types.h"
#include "arm11/fmt.h"
#include "hardware/gfx.h"
#include "util.h"
#include "arm11/console.h"
#include "arm11/font_6x10.h"
//set up the palette for color printing
static u16 colorTable[] = {
RGB8_to_565( 0, 0, 0), // faint black
RGB8_to_565(255, 0, 0), // bright red
RGB8_to_565( 0,255, 0), // bright green
RGB8_to_565(255,255, 0), // bright yellow
RGB8_to_565( 0, 0,255), // bright blue
RGB8_to_565(255, 0,255), // bright magenta
RGB8_to_565( 0,255,255), // bright cyan
RGB8_to_565(255,255,255), // bright white
RGB8_to_565( 64, 64, 64), // almost black
RGB8_to_565(224, 0, 0), // accent red
RGB8_to_565( 64,255, 64), // accent green
RGB8_to_565(255,255, 32), // accent yellow
RGB8_to_565( 64, 64,255), // accent blue
RGB8_to_565(255, 0,255), // bright magenta
RGB8_to_565( 0,255,255), // bright cyan
RGB8_to_565(192,192,192), // almost white
RGB8_to_565(128,128,128), // bright black
RGB8_to_565( 64, 0, 0), // faint red
RGB8_to_565( 0, 64, 0), // faint green
RGB8_to_565( 64, 64, 0), // faint yellow
RGB8_to_565( 0, 0, 64), // faint blue
RGB8_to_565( 64, 0, 64), // faint magenta
RGB8_to_565( 0, 64, 64), // faint cyan
RGB8_to_565( 96, 96, 96), // faint white
};
PrintConsole defaultConsole =
{
//Font:
{
default_font, //font gfx
0, //first ascii character in the set
256 //number of characters in the font set
},
(u16*)NULL,
0,0, //cursorX cursorY
0,0, //prevcursorX prevcursorY
53, //console width
24, //console height
0, //window x
0, //window y
53, //window width
24, //window height
3, //tab size
7, // foreground color
0, // background color
0, // flags
0, //print callback
false //console initialized
};
PrintConsole currentCopy;
PrintConsole* currentConsole = &currentCopy;
PrintConsole* consoleGetDefault(void){return &defaultConsole;}
void consolePrintChar(int c);
void consoleDrawChar(int c);
//---------------------------------------------------------------------------------
static void consoleCls(char mode) {
//---------------------------------------------------------------------------------
int i = 0;
int colTemp,rowTemp;
switch (mode)
{
case '[':
case '0':
{
colTemp = currentConsole->cursorX ;
rowTemp = currentConsole->cursorY ;
while(i++ < ((currentConsole->windowHeight * currentConsole->windowWidth) - (rowTemp * currentConsole->consoleWidth + colTemp)))
consolePrintChar(' ');
currentConsole->cursorX = colTemp;
currentConsole->cursorY = rowTemp;
break;
}
case '1':
{
colTemp = currentConsole->cursorX ;
rowTemp = currentConsole->cursorY ;
currentConsole->cursorY = 0;
currentConsole->cursorX = 0;
while (i++ < (rowTemp * currentConsole->windowWidth + colTemp))
consolePrintChar(' ');
currentConsole->cursorX = colTemp;
currentConsole->cursorY = rowTemp;
break;
}
case '2':
{
currentConsole->cursorY = 0;
currentConsole->cursorX = 0;
while(i++ < currentConsole->windowHeight * currentConsole->windowWidth)
consolePrintChar(' ');
currentConsole->cursorY = 0;
currentConsole->cursorX = 0;
break;
}
default: ;
}
}
//---------------------------------------------------------------------------------
static void consoleClearLine(char mode) {
//---------------------------------------------------------------------------------
int i = 0;
int colTemp;
switch (mode)
{
case '[':
case '0':
{
colTemp = currentConsole->cursorX ;
while(i++ < (currentConsole->windowWidth - colTemp)) {
consolePrintChar(' ');
}
currentConsole->cursorX = colTemp;
break;
}
case '1':
{
colTemp = currentConsole->cursorX ;
currentConsole->cursorX = 0;
while(i++ < ((currentConsole->windowWidth - colTemp)-2)) {
consolePrintChar(' ');
}
currentConsole->cursorX = colTemp;
break;
}
case '2':
{
colTemp = currentConsole->cursorX ;
currentConsole->cursorX = 0;
while(i++ < currentConsole->windowWidth) {
consolePrintChar(' ');
}
currentConsole->cursorX = colTemp;
break;
}
default: ;
}
}
__attribute__ ((format (scanf, 2, 3))) int fb_sscanf(const char *s, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
int ret = 0;
const char *const oldS = s;
while(*fmt)
{
if(*fmt == '%')
{
bool number = false;
switch(*++fmt)
{
case 'd':
*va_arg(args, int*) = atoi(s);
number = true;
ret++;
break;
case 'c':
*va_arg(args, char*) = *s++;
ret++;
break;
case 'n':
*va_arg(args, int*) = (int)(s - oldS);
break;
default: ;
}
if(number) while(*s >= '0' && *s <= '9') s++;
fmt++;
}
else
{
if(*fmt != *s) break;
fmt++;
s++;
}
}
va_end(args);
return ret;
}
//---------------------------------------------------------------------------------
ssize_t con_write(UNUSED struct _reent *r,UNUSED void *fd,const char *ptr, size_t len) {
//---------------------------------------------------------------------------------
char chr;
int i, count = 0;
const char *tmp = ptr;
if(!tmp || (int)len<=0) return -1;
i = 0;
while(i<(int)len) {
chr = *(tmp++);
i++; count++;
if ( chr == 0x1b && *tmp == '[' ) {
bool escaping = true;
const char *escapeseq = tmp++;
int escapelen = 1;
i++; count++;
do {
chr = *(tmp++);
i++; count++; escapelen++;
int parameter, assigned, consumed;
// make sure parameters are positive values and delimited by semicolon
if((chr >= '0' && chr <= '9') || chr == ';')
continue;
switch (chr) {
//---------------------------------------
// Cursor directional movement
//---------------------------------------
case 'A':
consumed = 0;
assigned = fb_sscanf(escapeseq,"[%dA%n", &parameter, &consumed);
if (assigned==0) parameter = 1;
if (consumed)
currentConsole->cursorY = (currentConsole->cursorY - parameter) < 0 ? 0 : currentConsole->cursorY - parameter;
escaping = false;
break;
case 'B':
consumed = 0;
assigned = fb_sscanf(escapeseq,"[%dB%n", &parameter, &consumed);
if (assigned==0) parameter = 1;
if (consumed)
currentConsole->cursorY = (currentConsole->cursorY + parameter) > currentConsole->windowHeight - 1 ? currentConsole->windowHeight - 1 : currentConsole->cursorY + parameter;
escaping = false;
break;
case 'C':
consumed = 0;
assigned = fb_sscanf(escapeseq,"[%dC%n", &parameter, &consumed);
if (assigned==0) parameter = 1;
if (consumed)
currentConsole->cursorX = (currentConsole->cursorX + parameter) > currentConsole->windowWidth - 1 ? currentConsole->windowWidth - 1 : currentConsole->cursorX + parameter;
escaping = false;
break;
case 'D':
consumed = 0;
assigned = fb_sscanf(escapeseq,"[%dD%n", &parameter, &consumed);
if (assigned==0) parameter = 1;
if (consumed)
currentConsole->cursorX = (currentConsole->cursorX - parameter) < 0 ? 0 : currentConsole->cursorX - parameter;
escaping = false;
break;
//---------------------------------------
// Cursor position movement
//---------------------------------------
case 'H':
case 'f':
{
int x, y;
char c;
if(fb_sscanf(escapeseq,"[%d;%d%c", &y, &x, &c) == 3 && (c == 'f' || c == 'H')) {
currentConsole->cursorX = x;
currentConsole->cursorY = y;
escaping = false;
break;
}
x = y = 1;
if(fb_sscanf(escapeseq,"[%d;%c", &y, &c) == 2 && (c == 'f' || c == 'H')) {
currentConsole->cursorX = x;
currentConsole->cursorY = y;
escaping = false;
break;
}
x = y = 1;
if(fb_sscanf(escapeseq,"[;%d%c", &x, &c) == 2 && (c == 'f' || c == 'H')) {
currentConsole->cursorX = x;
currentConsole->cursorY = y;
escaping = false;
break;
}
x = y = 1;
if(fb_sscanf(escapeseq,"[;%c", &c) == 1 && (c == 'f' || c == 'H')) {
currentConsole->cursorX = x;
currentConsole->cursorY = y;
escaping = false;
break;
}
// invalid format
escaping = false;
break;
}
//---------------------------------------
// Screen clear
//---------------------------------------
case 'J':
if(escapelen <= 3)
consoleCls(escapeseq[escapelen-2]);
escaping = false;
break;
//---------------------------------------
// Line clear
//---------------------------------------
case 'K':
if(escapelen <= 3)
consoleClearLine(escapeseq[escapelen-2]);
escaping = false;
break;
//---------------------------------------
// Save cursor position
//---------------------------------------
case 's':
if(escapelen == 2) {
currentConsole->prevCursorX = currentConsole->cursorX ;
currentConsole->prevCursorY = currentConsole->cursorY ;
}
escaping = false;
break;
//---------------------------------------
// Load cursor position
//---------------------------------------
case 'u':
if(escapelen == 2) {
currentConsole->cursorX = currentConsole->prevCursorX ;
currentConsole->cursorY = currentConsole->prevCursorY ;
}
escaping = false;
break;
//---------------------------------------
// Color scan codes
//---------------------------------------
case 'm':
escapeseq++;
escapelen--;
do {
parameter = 0;
if (escapelen == 1) {
consumed = 1;
} else if (memchr(escapeseq,';',escapelen)) {
fb_sscanf(escapeseq,"%d;%n", &parameter, &consumed);
} else {
fb_sscanf(escapeseq,"%dm%n", &parameter, &consumed);
}
escapeseq += consumed;
escapelen -= consumed;
switch(parameter) {
case 0: // reset
currentConsole->flags = 0;
currentConsole->bg = 0;
currentConsole->fg = 7;
break;
case 1: // bold
currentConsole->flags &= ~CONSOLE_COLOR_FAINT;
currentConsole->flags |= CONSOLE_COLOR_BOLD;
break;
case 2: // faint
currentConsole->flags &= ~CONSOLE_COLOR_BOLD;
currentConsole->flags |= CONSOLE_COLOR_FAINT;
break;
case 3: // italic
currentConsole->flags |= CONSOLE_ITALIC;
break;
case 4: // underline
currentConsole->flags |= CONSOLE_UNDERLINE;
break;
case 5: // blink slow
currentConsole->flags &= ~CONSOLE_BLINK_FAST;
currentConsole->flags |= CONSOLE_BLINK_SLOW;
break;
case 6: // blink fast
currentConsole->flags &= ~CONSOLE_BLINK_SLOW;
currentConsole->flags |= CONSOLE_BLINK_FAST;
break;
case 7: // reverse video
currentConsole->flags |= CONSOLE_COLOR_REVERSE;
break;
case 8: // conceal
currentConsole->flags |= CONSOLE_CONCEAL;
break;
case 9: // crossed-out
currentConsole->flags |= CONSOLE_CROSSED_OUT;
break;
case 21: // bold off
currentConsole->flags &= ~CONSOLE_COLOR_BOLD;
break;
case 22: // normal color
currentConsole->flags &= ~CONSOLE_COLOR_BOLD;
currentConsole->flags &= ~CONSOLE_COLOR_FAINT;
break;
case 23: // italic off
currentConsole->flags &= ~CONSOLE_ITALIC;
break;
case 24: // underline off
currentConsole->flags &= ~CONSOLE_UNDERLINE;
break;
case 25: // blink off
currentConsole->flags &= ~CONSOLE_BLINK_SLOW;
currentConsole->flags &= ~CONSOLE_BLINK_FAST;
break;
case 27: // reverse off
currentConsole->flags &= ~CONSOLE_COLOR_REVERSE;
break;
case 29: // crossed-out off
currentConsole->flags &= ~CONSOLE_CROSSED_OUT;
break;
case 30 ... 37: // writing color
currentConsole->fg = parameter - 30;
break;
case 39: // reset foreground color
currentConsole->fg = 7;
break;
case 40 ... 47: // screen color
currentConsole->bg = parameter - 40;
break;
case 49: // reset background color
currentConsole->fg = 0;
break;
default: ;
}
} while (escapelen > 0);
escaping = false;
break;
default:
// some sort of unsupported escape; just gloss over it
escaping = false;
break;
}
} while (escaping);
continue;
}
consolePrintChar(chr);
}
return count;
}
//---------------------------------------------------------------------------------
PrintConsole* consoleInit(u8 screen, PrintConsole* console) {
//---------------------------------------------------------------------------------
if(console) {
currentConsole = console;
} else {
console = currentConsole;
}
*currentConsole = defaultConsole;
console->consoleInitialised = 1;
//gfxSetScreenFormat(screen,GSP_RGB565_OES);
GFX_setDoubleBuffering(screen, false);
console->frameBuffer = (u16*)GFX_getFramebuffer(screen);
if(screen==SCREEN_TOP) {
console->consoleWidth = 66;
console->windowWidth = 66;
}
consoleCls('2');
return currentConsole;
}
//---------------------------------------------------------------------------------
PrintConsole *consoleSelect(PrintConsole* console){
//---------------------------------------------------------------------------------
PrintConsole *tmp = currentConsole;
currentConsole = console;
return tmp;
}
//---------------------------------------------------------------------------------
PrintConsole *consoleGet(void){
//---------------------------------------------------------------------------------
return currentConsole;
}
//---------------------------------------------------------------------------------
u16 consoleGetFgColor(void){
//---------------------------------------------------------------------------------
return colorTable[currentConsole->fg];
}
//---------------------------------------------------------------------------------
void consoleSetFont(PrintConsole* console, ConsoleFont* font){
//---------------------------------------------------------------------------------
if(!console) console = currentConsole;
console->font = *font;
}
//---------------------------------------------------------------------------------
static void newRow() {
//---------------------------------------------------------------------------------
currentConsole->cursorY ++;
if(currentConsole->cursorY >= currentConsole->windowHeight) {
currentConsole->cursorY --;
u16 *dst = &currentConsole->frameBuffer[(currentConsole->windowX * 6 * 240) + (239 - (currentConsole->windowY * 10))];
u16 *src = dst - 10;
int i,j;
for (i=0; i<currentConsole->windowWidth*6; i++) {
u32 *from = (u32*)((int)src & ~3);
u32 *to = (u32*)((int)dst & ~3);
for (j=0;j<(((currentConsole->windowHeight-1)*10)/2);j++) *(to--) = *(from--);
dst += 240;
src += 240;
}
consoleClearLine('2');
}
}
//---------------------------------------------------------------------------------
void consoleDrawChar(int c) {
//---------------------------------------------------------------------------------
c -= currentConsole->font.asciiOffset;
if ( c < 0 || c > currentConsole->font.numChars ) return;
const u8 *fontdata = currentConsole->font.gfx + (10 * c);
int writingColor = currentConsole->fg;
int screenColor = currentConsole->bg;
if (currentConsole->flags & CONSOLE_COLOR_BOLD) {
writingColor += 8;
} else if (currentConsole->flags & CONSOLE_COLOR_FAINT) {
writingColor += 16;
}
if (currentConsole->flags & CONSOLE_COLOR_REVERSE) {
int tmp = writingColor;
writingColor = screenColor;
screenColor = tmp;
}
u16 bg = colorTable[screenColor];
u16 fg = colorTable[writingColor];
u8 b1 = *(fontdata++);
u8 b2 = *(fontdata++);
u8 b3 = *(fontdata++);
u8 b4 = *(fontdata++);
u8 b5 = *(fontdata++);
u8 b6 = *(fontdata++);
u8 b7 = *(fontdata++);
u8 b8 = *(fontdata++);
u8 b9 = *(fontdata++);
u8 b10 = *(fontdata++);
if (currentConsole->flags & CONSOLE_UNDERLINE) b10 = 0xff;
if (currentConsole->flags & CONSOLE_CROSSED_OUT) b5 = 0xff;
u8 mask = 0x80;
int i;
int x = (currentConsole->cursorX + currentConsole->windowX) * 6;
int y = ((currentConsole->cursorY + currentConsole->windowY) * 10);
u16 *screen = &currentConsole->frameBuffer[(x * 240) + (239 - (y + 9))];
for (i=0;i<6;i++) {
if (b10 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }
if (b9 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }
if (b8 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }
if (b7 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }
if (b6 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }
if (b5 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }
if (b4 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }
if (b3 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }
if (b2 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }
if (b1 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }
mask >>= 1;
screen += 240 - 10;
}
}
//---------------------------------------------------------------------------------
void consolePrintChar(int c) {
//---------------------------------------------------------------------------------
if (c==0) return;
if(currentConsole->PrintChar)
if(currentConsole->PrintChar(currentConsole, c))
return;
if(currentConsole->cursorX >= currentConsole->windowWidth) {
currentConsole->cursorX = 0;
newRow();
}
switch(c) {
/*
The only special characters we will handle are tab (\t), carriage return (\r), line feed (\n)
and backspace (\b).
Carriage return & line feed will function the same: go to next line and put cursor at the beginning.
For everything else, use VT sequences.
Reason: VT sequences are more specific to the task of cursor placement.
The special escape sequences \b \f & \v are archaic and non-portable.
*/
case 8:
currentConsole->cursorX--;
if(currentConsole->cursorX < 0) {
if(currentConsole->cursorY > 0) {
currentConsole->cursorX = currentConsole->windowX - 1;
currentConsole->cursorY--;
} else {
currentConsole->cursorX = 0;
}
}
consoleDrawChar(' ');
break;
case 9:
currentConsole->cursorX += currentConsole->tabSize - ((currentConsole->cursorX)%(currentConsole->tabSize));
break;
case 10:
newRow();
// falls through
case 13:
currentConsole->cursorX = 0;
break;
default:
consoleDrawChar(c);
++currentConsole->cursorX ;
break;
}
}
//---------------------------------------------------------------------------------
void consoleClear(void) {
//---------------------------------------------------------------------------------
ee_printf("\x1b[2J");
}
//---------------------------------------------------------------------------------
void consoleSetWindow(PrintConsole* console, int x, int y, int width, int height){
//---------------------------------------------------------------------------------
if(!console) console = currentConsole;
console->windowWidth = width;
console->windowHeight = height;
console->windowX = x;
console->windowY = y;
console->cursorX = 0;
console->cursorY = 0;
}
void drawConsoleWindow(PrintConsole* console, int thickness, u8 colorIndex) {
if(colorIndex >= 16) return;
if(!console) console = currentConsole;
int startx = console->windowX * 8 - thickness;
int endx = (console->windowX + console->windowWidth) * 8 + thickness;
int starty = (console->windowY - 1) * 8 - thickness;
int endy = console->windowHeight * 8 + thickness;
u16 color = colorTable[colorIndex];
// upper line
for(int y = starty; y < starty + thickness; y++)
for(int x = startx; x < endx; x++)
{
u16 *screen = &currentConsole->frameBuffer[(x * 240) + (239 - (y + 7))];
*screen = color;
}
// lower line
for(int y = endy; y > endy - thickness; y--)
for(int x = startx; x < endx; x++)
{
u16 *screen = &currentConsole->frameBuffer[(x * 240) + (239 - (y + 7))];
*screen = color;
}
// left and right
for(int y = starty; y < endy; y++)
{
for(int i = 0; i < thickness; i++)
{
u16 *screen = &currentConsole->frameBuffer[((startx + i) * 240) + (239 - (y + 7))];
*screen = color;
screen = &currentConsole->frameBuffer[((endx - thickness + i) * 240) + (239 - (y + 7))];
*screen = color;
}
}
}
void consoleSetCursor(PrintConsole* console, int x, int y) {
console->cursorX = x;
console->cursorY = y;
}
u16 consoleGetRGB565Color(u8 colorIndex) {
if(colorIndex >= arrayEntries(colorTable))
return 0;
return colorTable[colorIndex];
}

Some files were not shown because too many files have changed in this diff Show More