Compare commits
173 Commits
alpha_2020
...
master
Author | SHA1 | Date |
---|---|---|
![]() |
6b882e9395 | |
![]() |
4e4c2aa2b5 | |
![]() |
dd90d498c4 | |
![]() |
877f7c61d0 | |
![]() |
7a7190baea | |
![]() |
edd43a6fcc | |
![]() |
50e2f30e0d | |
![]() |
79b2457e8b | |
![]() |
5356e5c89a | |
![]() |
67ce019b36 | |
![]() |
41db8760a6 | |
![]() |
3a70cdc27f | |
![]() |
b1c66e24a2 | |
![]() |
f7efd62ea9 | |
![]() |
073daac2bb | |
![]() |
15436e02a7 | |
![]() |
3e91716c80 | |
![]() |
f9786b14a1 | |
![]() |
bd5b207106 | |
![]() |
7c8c3d6fe8 | |
![]() |
6cf6059023 | |
![]() |
1ad621d4f4 | |
![]() |
9f331c24f7 | |
![]() |
3ffb706f3b | |
![]() |
c85a4b1b57 | |
![]() |
6db20e190c | |
![]() |
d7f701f02a | |
![]() |
2bca9b04b6 | |
![]() |
678cbd9ae3 | |
![]() |
479069d039 | |
![]() |
99cf0fdacc | |
![]() |
9d13ad3722 | |
![]() |
07bdaf521d | |
![]() |
e14704181c | |
![]() |
63e4422db1 | |
![]() |
b554c7c35c | |
![]() |
5f46a967a8 | |
![]() |
dc5ac1749f | |
![]() |
855f6b131a | |
![]() |
e77b04f089 | |
![]() |
ddba28b226 | |
![]() |
8db77d523e | |
![]() |
4377d28d14 | |
![]() |
1ca27c22f6 | |
![]() |
6766b224dc | |
![]() |
a3c8f76e82 | |
![]() |
92c591da22 | |
![]() |
0f55ad941c | |
![]() |
cf7d1915e0 | |
![]() |
8ecc7ce458 | |
![]() |
4f96bae9d3 | |
![]() |
014c341e67 | |
![]() |
726a4f3355 | |
![]() |
30351188a4 | |
![]() |
cecd0d31f3 | |
![]() |
3d8a24769d | |
![]() |
1e5e1ea6a9 | |
![]() |
5e103deecc | |
![]() |
80f48ca43e | |
![]() |
a70673dea7 | |
![]() |
99d6b1e1ea | |
![]() |
6298503e6b | |
![]() |
cdacbc7dc5 | |
![]() |
edaa5fb2cb | |
![]() |
d80588ffc4 | |
![]() |
93d5cdf045 | |
![]() |
45830c8c68 | |
![]() |
c171c4da1d | |
![]() |
b1739994a2 | |
![]() |
6bfccaee80 | |
![]() |
b710d8e326 | |
![]() |
834c0ffbbf | |
![]() |
b1d2b5a84a | |
![]() |
09622b88f8 | |
![]() |
48448c749c | |
![]() |
a13499c49e | |
![]() |
1fe529f4c5 | |
![]() |
bd6bc4fd54 | |
![]() |
ee21e3edb0 | |
![]() |
6b5abf383d | |
![]() |
56bf27a026 | |
![]() |
3183839120 | |
![]() |
5ab356a248 | |
![]() |
9bd9497315 | |
![]() |
25b1f794c2 | |
![]() |
9e44587f1c | |
![]() |
dbaad7d09c | |
![]() |
4e86b0c6bf | |
![]() |
b128dd4575 | |
![]() |
a588af0b3c | |
![]() |
dd4f51334f | |
![]() |
97bdad5710 | |
![]() |
f486ba2b9f | |
![]() |
8f86f79461 | |
![]() |
78fd101c66 | |
![]() |
c139ceb720 | |
![]() |
92f3208daa | |
![]() |
f9f47df59e | |
![]() |
9d54442c42 | |
![]() |
b8b75d784c | |
![]() |
5714b5eb16 | |
![]() |
dc0320615b | |
![]() |
3a31110673 | |
![]() |
1c680e7d52 | |
![]() |
4a6603d110 | |
![]() |
2222e54f0f | |
![]() |
782596facd | |
![]() |
a9fcf853bb | |
![]() |
9756e2eafc | |
![]() |
15cf1bffd5 | |
![]() |
247cb19cb5 | |
![]() |
35243abed0 | |
![]() |
37f3df4a52 | |
![]() |
d7baad122a | |
![]() |
b09e3a0eee | |
![]() |
6129451b75 | |
![]() |
f59f596a2b | |
![]() |
434f714ef1 | |
![]() |
82d54b341c | |
![]() |
fa4ef131d9 | |
![]() |
2308e59c85 | |
![]() |
67f42f764c | |
![]() |
1375224a6e | |
![]() |
83fe7a9961 | |
![]() |
6899a7a892 | |
![]() |
eee47c5de1 | |
![]() |
157a973006 | |
![]() |
1ad3dcc0ef | |
![]() |
d2e1159113 | |
![]() |
f5b40f1156 | |
![]() |
675db2942f | |
![]() |
c4f6f3dabe | |
![]() |
2c8db472ab | |
![]() |
76092e9093 | |
![]() |
6538c56106 | |
![]() |
167db2f20d | |
![]() |
7f3c6762c7 | |
![]() |
b972f75adf | |
![]() |
caca936a66 | |
![]() |
a9881d3a32 | |
![]() |
3fe3f2cbba | |
![]() |
ed91a742f1 | |
![]() |
3ef62b0ac1 | |
![]() |
a6756d6115 | |
![]() |
db12bb5ab2 | |
![]() |
d5e3a08f99 | |
![]() |
c3a1458541 | |
![]() |
8e5562a9f7 | |
![]() |
f7785c67e8 | |
![]() |
2224e23022 | |
![]() |
c2a9cde160 | |
![]() |
bf47990240 | |
![]() |
07c489865c | |
![]() |
d709c76b06 | |
![]() |
9553fcbbdb | |
![]() |
57844df7fc | |
![]() |
5af5a65bc7 | |
![]() |
ac429d2e4b | |
![]() |
f2fb5a62b3 | |
![]() |
d5671a39d6 | |
![]() |
ff8ebb9ff6 | |
![]() |
d22a248b40 | |
![]() |
b5ab37cb2c | |
![]() |
411aa70b0f | |
![]() |
36cc930c1f | |
![]() |
92ddc5e61b | |
![]() |
d7cfb126ec | |
![]() |
a5ae7762f7 | |
![]() |
e2c295d784 | |
![]() |
8a6e9cdac9 | |
![]() |
ee96be075c | |
![]() |
529c9535f2 | |
![]() |
794111d802 |
|
@ -0,0 +1,52 @@
|
|||
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
|
|
@ -1,11 +1,9 @@
|
|||
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
|
||||
/.*
|
||||
!/.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*.*
|
|
@ -0,0 +1,9 @@
|
|||
[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
|
56
Makefile
56
Makefile
|
@ -9,16 +9,25 @@ 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
|
||||
|
@ -30,35 +39,66 @@ all: checkarm9 checkarm11 $(TARGET).firm
|
|||
|
||||
#---------------------------------------------------------------------------------
|
||||
checkarm9:
|
||||
@$(MAKE) -j4 --no-print-directory -C arm9
|
||||
@$(MAKE) -j$(NPROC) --no-print-directory -C arm9
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
checkarm11:
|
||||
@$(MAKE) -j4 --no-print-directory -C arm11
|
||||
@$(MAKE) -j$(NPROC) --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) -j4 --no-print-directory -C arm9
|
||||
@$(MAKE) -j$(NPROC) --no-print-directory -C arm9
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
arm11/$(TARGET)11.bin:
|
||||
@$(MAKE) -j4 --no-print-directory -C arm11
|
||||
@$(MAKE) -j$(NPROC) --no-print-directory -C arm11
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@$(MAKE) --no-print-directory -C arm9 clean
|
||||
@$(MAKE) --no-print-directory -C arm11 clean
|
||||
rm -f $(TARGET).firm *.7z
|
||||
rm -fr $(TARGET).firm *.7z nightly
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
release: clean
|
||||
@$(MAKE) -j4 --no-print-directory -C arm9 NO_DEBUG=1
|
||||
@$(MAKE) -j4 --no-print-directory -C arm11 NO_DEBUG=1
|
||||
@$(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
|
||||
@7z a -mx -m0=ARM -m1=LZMA $(TARGET)$(VERS_STRING).7z $(TARGET).firm
|
||||
@7z u -mx -m0=PPMD $(TARGET)$(VERS_STRING).7z LICENSE.txt README.md
|
||||
@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
|
||||
|
|
299
README.md
299
README.md
|
@ -1,44 +1,276 @@
|
|||
# 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 a bare metal app for running GBA homebrew/games using the 3DS builtin 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.
|
||||
|
||||
## Disclaimer
|
||||
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.
|
||||
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.
|
||||
|
||||
## 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)
|
||||
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.
|
||||
|
||||
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`.
|
||||
## 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.
|
||||
|
||||
## Known issues
|
||||
## 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
|
||||
This section is reserved for a listing of known issues. At present only this remains:
|
||||
* Sleep mode is not fully implemented.
|
||||
* Save type detection may still fail for certain games using EEPROM.
|
||||
* No settings (including brightness control), no cheats and other enhancements.
|
||||
* 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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
## 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.
|
||||
## 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).
|
||||
|
||||
## Troubleshooting
|
||||
Known problems and the solution.
|
||||
## 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.
|
||||
|
||||
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.
|
||||
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`.
|
||||
|
||||
## License
|
||||
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.
|
||||
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.
|
||||
|
||||
## Thanks to...
|
||||
* **yellows8**
|
||||
|
@ -47,12 +279,17 @@ You may use this under the terms of the GNU General Public License GPL v3 or und
|
|||
* **Normmatt**
|
||||
* **WinterMute**
|
||||
* **ctrulib devs**
|
||||
* **Luma 3DS devs**
|
||||
* **LumaTeam**
|
||||
* **devkitPro**
|
||||
* **ChaN**
|
||||
* **ChaN** (fatfs)
|
||||
* **benhoyt** (inih)
|
||||
* **fastboot3DS project**
|
||||
* **Wolfvak, Sono and all the other people in #GodMode9 on IRC/Discord**
|
||||
* **endrift, Extrems and all the other people in #mgba on Freenode**
|
||||
* **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)**
|
||||
* ...everyone who contributed to **3dbrew.org**
|
||||
|
||||
Copyright (C) 2020 derrek, profi200, d0k3
|
||||
Copyright (C) 2024 derrek, profi200, d0k3
|
|
@ -8,6 +8,7 @@ endif
|
|||
|
||||
TOPDIR ?= $(CURDIR)
|
||||
include $(DEVKITARM)/base_rules
|
||||
include $(TOPDIR)/../libraries/libn3ds/libn3ds11.mk
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# TARGET is the name of the output
|
||||
|
@ -18,12 +19,10 @@ include $(DEVKITARM)/base_rules
|
|||
#---------------------------------------------------------------------------------
|
||||
#TARGET := $(notdir $(CURDIR))
|
||||
BUILD := build
|
||||
SOURCES := ../source ../source/hardware ../source/arm11 \
|
||||
../source/arm11/allocator ../source/arm11/hardware \
|
||||
../source/arm11/util/rbtree
|
||||
SOURCES += ../source ../source/arm11 ../libraries/inih
|
||||
DATA :=
|
||||
INCLUDES := ../include
|
||||
DEFINES := -DARM11 -D_3DS -DVERS_STRING=\"$(VERS_STRING)\" \
|
||||
INCLUDES += ../include ../libraries
|
||||
DEFINES := -D__ARM11__ -D__3DS__ -DLIBN3DS_LEGACY=1 -DVERS_STRING=\"$(VERS_STRING)\" \
|
||||
-DVERS_MAJOR=$(VERS_MAJOR) -DVERS_MINOR=$(VERS_MINOR)
|
||||
ASSETS :=
|
||||
|
||||
|
@ -34,19 +33,25 @@ endif
|
|||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -march=armv6k+vfpv2 -mtune=mpcore -mfloat-abi=hard -mtp=soft -marm -mthumb-interwork
|
||||
ARCH := -march=armv6k+vfpv2 -mtune=mpcore -mfloat-abi=hard -mtp=soft -marm -mthumb-interwork -masm-syntax-unified
|
||||
|
||||
CFLAGS := $(ARCH) -std=gnu17 -O2 -g -flto -mword-relocations -ffunction-sections \
|
||||
-fno-math-errno -Wall -Wextra -Wno-unused-function
|
||||
CFLAGS := $(ARCH) -std=c23 -O2 -gdwarf-4 -flto -mword-relocations \
|
||||
-ffunction-sections -fno-math-errno -Wall -Wextra
|
||||
CFLAGS += $(INCLUDE) $(DEFINES)
|
||||
|
||||
CXXFLAGS := $(ARCH) -std=c++17 -O2 -g -flto -fno-rtti -fno-exceptions \
|
||||
-mword-relocations -ffunction-sections -fno-math-errno -Wall -Wextra \
|
||||
-Wno-unused-function
|
||||
CXXFLAGS := $(ARCH) -std=c++23 -O2 -gdwarf-4 -flto -fno-rtti -fno-exceptions \
|
||||
-mword-relocations -ffunction-sections -fno-math-errno -Wall -Wextra
|
||||
CXXFLAGS += $(INCLUDE) $(DEFINES)
|
||||
|
||||
ASFLAGS := $(ARCH) -g -flto $(INCLUDE) $(DEFINES)
|
||||
LDFLAGS = $(ARCH) -g -flto -specs=../arm11.specs -Wl,-Map,$(notdir $*.map) -nostartfiles
|
||||
ASFLAGS := $(ARCH) -gdwarf-4 -flto $(INCLUDE) $(DEFINES)
|
||||
LDFLAGS = $(ARCH) -gdwarf-4 -flto -specs=../arm11.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
|
||||
|
||||
LIBS := -lm
|
||||
|
||||
|
@ -188,4 +193,3 @@ endef
|
|||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------------
|
|
@ -8,6 +8,7 @@ endif
|
|||
|
||||
TOPDIR ?= $(CURDIR)
|
||||
include $(DEVKITARM)/base_rules
|
||||
include $(TOPDIR)/../libraries/libn3ds/libn3ds9.mk
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# TARGET is the name of the output
|
||||
|
@ -18,10 +19,10 @@ include $(DEVKITARM)/base_rules
|
|||
#---------------------------------------------------------------------------------
|
||||
#TARGET := $(notdir $(CURDIR))
|
||||
BUILD := build
|
||||
SOURCES := ../source ../source/hardware ../source/arm9 ../source/arm9/hardware ../thirdparty/fatfs
|
||||
SOURCES += ../source/arm9
|
||||
DATA :=
|
||||
INCLUDES := ../include ../thirdparty
|
||||
DEFINES := -DARM9 -D_3DS -DVERS_STRING=\"$(VERS_STRING)\" \
|
||||
INCLUDES += ../include
|
||||
DEFINES := -D__ARM9__ -D__3DS__ -DLIBN3DS_LEGACY=1 -DVERS_STRING=\"$(VERS_STRING)\" \
|
||||
-DVERS_MAJOR=$(VERS_MAJOR) -DVERS_MINOR=$(VERS_MINOR)
|
||||
|
||||
ifneq ($(strip $(NO_DEBUG)),)
|
||||
|
@ -31,18 +32,25 @@ endif
|
|||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -march=armv5te -mtune=arm946e-s -mfloat-abi=soft -mtp=soft -marm -mthumb-interwork
|
||||
ARCH := -march=armv5te -mtune=arm946e-s -mfloat-abi=soft -mtp=soft -marm -mthumb-interwork -masm-syntax-unified
|
||||
|
||||
CFLAGS := $(ARCH) -std=c17 -O2 -g -flto -mword-relocations \
|
||||
CFLAGS := $(ARCH) -std=c23 -O2 -gdwarf-4 -flto -mword-relocations \
|
||||
-ffunction-sections -Wall -Wextra
|
||||
CFLAGS += $(INCLUDE) $(DEFINES)
|
||||
|
||||
CXXFLAGS := $(ARCH) -std=c++17 -O2 -g -flto -fno-rtti -fno-exceptions \
|
||||
CXXFLAGS := $(ARCH) -std=c++23 -O2 -gdwarf-4 -flto -fno-rtti -fno-exceptions \
|
||||
-mword-relocations -ffunction-sections -Wall -Wextra
|
||||
CXXFLAGS += $(INCLUDE) $(DEFINES)
|
||||
|
||||
ASFLAGS := $(ARCH) -g -flto $(INCLUDE) $(DEFINES)
|
||||
LDFLAGS = $(ARCH) -g -flto -specs=../arm9.specs -Wl,-Map,$(notdir $*.map) -nostartfiles
|
||||
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
|
||||
|
||||
LIBS :=
|
||||
|
||||
|
|
160
include/arm.h
160
include/arm.h
|
@ -1,160 +0,0 @@
|
|||
#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_STANDALONE(name) \
|
||||
static inline void __##name(void) \
|
||||
{ \
|
||||
__asm__ volatile(#name : : : "memory"); \
|
||||
}
|
||||
|
||||
#define MAKE_GET_REG(name, inst) \
|
||||
static inline u32 __##name(void) \
|
||||
{ \
|
||||
u32 reg; \
|
||||
__asm__ volatile(inst : "=r" (reg) : ); \
|
||||
return reg; \
|
||||
}
|
||||
|
||||
#define MAKE_SET_REG_ZERO(name, inst) \
|
||||
static inline void __##name(void) \
|
||||
{ \
|
||||
__asm__ volatile(inst : : "r" (0) : "memory"); \
|
||||
}
|
||||
|
||||
#define MAKE_SET_REG(name, inst) \
|
||||
static inline void __##name(u32 reg) \
|
||||
{ \
|
||||
__asm__ volatile(inst : : "r" (reg) : "memory"); \
|
||||
}
|
||||
|
||||
|
||||
#if !__thumb__
|
||||
// Program status register
|
||||
MAKE_GET_REG(getCpsr, "mrs %0, cpsr")
|
||||
MAKE_SET_REG(setCpsr_c, "msr cpsr_c, %0")
|
||||
MAKE_SET_REG(setCpsr, "msr cpsr_cxsf, %0")
|
||||
MAKE_GET_REG(getSpsr, "mrs %0, spsr")
|
||||
MAKE_SET_REG(setSpsr_c, "msr spsr_c, %0")
|
||||
MAKE_SET_REG(setSpsr, "msr spsr_cxsf, %0")
|
||||
|
||||
// Control Register
|
||||
MAKE_GET_REG(getCr, "mrc p15, 0, %0, c1, c0, 0")
|
||||
MAKE_SET_REG(setCr, "mcr p15, 0, %0, c1, c0, 0")
|
||||
#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_STANDALONE(wfi)
|
||||
MAKE_STANDALONE(wfe)
|
||||
MAKE_STANDALONE(sev)
|
||||
|
||||
#if !__thumb__
|
||||
static inline u32 __getCpuId(void)
|
||||
{
|
||||
u32 cpuId;
|
||||
__asm__("mrc p15, 0, %0, c0, c0, 5" : "=r" (cpuId) : );
|
||||
return cpuId & 3;
|
||||
}
|
||||
|
||||
// Flush Prefetch Buffer
|
||||
// Data Synchronization Barrier
|
||||
// Data Memory Barrier
|
||||
MAKE_SET_REG_ZERO(isb, "mcr p15, 0, %0, c7, c5, 4")
|
||||
MAKE_SET_REG_ZERO(dsb, "mcr p15, 0, %0, c7, c10, 4")
|
||||
MAKE_SET_REG_ZERO(dmb, "mcr p15, 0, %0, c7, c10, 5")
|
||||
|
||||
// Auxiliary Control Register
|
||||
MAKE_GET_REG(getAcr, "mrc p15, 0, %0, c1, c0, 1")
|
||||
MAKE_SET_REG(setAcr, "mcr p15, 0, %0, c1, c0, 1")
|
||||
|
||||
// Translation Table Base Register 0
|
||||
MAKE_GET_REG(getTtbr0, "mrc p15, 0, %0, c2, c0, 0")
|
||||
MAKE_SET_REG(setTtbr0, "mcr p15, 0, %0, c2, c0, 0")
|
||||
|
||||
// Translation Table Base Register 1
|
||||
MAKE_GET_REG(getTtbr1, "mrc p15, 0, %0, c2, c0, 1")
|
||||
MAKE_SET_REG(setTtbr1, "mcr p15, 0, %0, c2, c0, 1")
|
||||
|
||||
// Translation Table Base Control Register
|
||||
MAKE_GET_REG(getTtbcr, "mrc p15, 0, %0, c2, c0, 2")
|
||||
MAKE_SET_REG(setTtbcr, "mcr p15, 0, %0, c2, c0, 2")
|
||||
|
||||
// Domain Access Control Register
|
||||
MAKE_GET_REG(getDacr, "mrc p15, 0, %0, c3, c0, 0")
|
||||
MAKE_SET_REG(setDacr, "mcr p15, 0, %0, c3, c0, 0")
|
||||
|
||||
// FCSE PID Register
|
||||
MAKE_GET_REG(getFcsepidr, "mrc p15, 0, %0, c13, c0, 0")
|
||||
MAKE_SET_REG(setFcsepidr, "mcr p15, 0, %0, c13, c0, 0")
|
||||
|
||||
// Context ID Register
|
||||
MAKE_GET_REG(getCidr, "mrc p15, 0, %0, c13, c0, 1")
|
||||
MAKE_SET_REG(setCidr, "mcr p15, 0, %0, c13, c0, 1")
|
||||
#endif // if !__thumb__
|
||||
|
||||
#elif ARM9
|
||||
|
||||
#if !__thumb__
|
||||
MAKE_SET_REG_ZERO(wfi, "mcr p15, 0, %0, c7, c0, 4")
|
||||
#endif // if !__thumb__
|
||||
#endif // ifdef ARM11
|
||||
|
||||
#undef MAKE_STANDALONE
|
||||
#undef MAKE_GET_REG
|
||||
#undef MAKE_SET_REG_ZERO
|
||||
#undef MAKE_SET_REG
|
||||
|
||||
#endif // if !__ASSEMBLER__
|
|
@ -1,47 +0,0 @@
|
|||
/**
|
||||
* @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);
|
|
@ -0,0 +1,89 @@
|
|||
#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
|
|
@ -0,0 +1,76 @@
|
|||
#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
|
|
@ -1,192 +0,0 @@
|
|||
#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
|
|
@ -1,51 +0,0 @@
|
|||
#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();
|
||||
noreturn void panicMsg(const char *msg);
|
||||
//void debugMemdump(const char *filepath, void *mem, size_t size);
|
||||
|
||||
// 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" : :);
|
||||
}*/
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
/*
|
||||
* This file is part of fastboot 3DS
|
||||
* Copyright (C) 2017 derrek, profi200
|
||||
* 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
|
||||
|
@ -18,10 +18,16 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "types.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
noreturn void panic();
|
||||
noreturn void panicMsg(const char *msg);
|
||||
//void dumpMem(u8 *mem, u32 size, char *filepath);
|
||||
void convert160pFrameFast(void);
|
||||
void convert240pFrameFast(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
/*
|
||||
* This file is part of fastboot 3DS
|
||||
* Copyright (C) 2017 derrek, profi200
|
||||
* 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
|
||||
|
@ -22,4 +22,13 @@
|
|||
|
||||
|
||||
|
||||
void deinitCpu(void);
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void makeOpenBusPaddingFast(u32 *romEnd);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
|
@ -1,7 +1,34 @@
|
|||
#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
|
|
@ -1,48 +0,0 @@
|
|||
#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
|
File diff suppressed because it is too large
Load Diff
|
@ -1,73 +0,0 @@
|
|||
#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},
|
||||
};
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
/*
|
||||
* This file is part of fastboot 3DS
|
||||
* Copyright (C) 2019 derrek, profi200
|
||||
* 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
|
||||
|
@ -21,11 +21,25 @@
|
|||
#include "types.h"
|
||||
|
||||
|
||||
#define SPIFLASH_CMD_RDSR (0x05)
|
||||
#define SPIFLASH_CMD_READ (0x03)
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#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];
|
||||
|
||||
|
||||
|
||||
// true if spiflash is installed, false otherwise
|
||||
bool spiflash_get_status(void);
|
||||
void spiflash_read(u32 offset, u32 size, u32 *buf);
|
||||
void patchGbaGpuCmdList(const u8 scaleType, const bool useSecondTexture);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
|
@ -1,80 +0,0 @@
|
|||
#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.
|
|
@ -1,56 +0,0 @@
|
|||
#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);
|
|
@ -1,186 +0,0 @@
|
|||
#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;
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
#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);
|
|
@ -1,769 +0,0 @@
|
|||
// 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.
|
||||
///@}
|
|
@ -1,41 +0,0 @@
|
|||
#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)))
|
|
@ -1,81 +0,0 @@
|
|||
#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);
|
|
@ -1,105 +0,0 @@
|
|||
#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);
|
|
@ -1,145 +0,0 @@
|
|||
#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);
|
|
@ -1,236 +0,0 @@
|
|||
#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
|
|
@ -1,132 +0,0 @@
|
|||
#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_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);
|
|
@ -1,40 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
|
||||
// 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(void);
|
||||
void LGYFB_processFrame(void);
|
||||
void LGYFB_deinit(void);
|
||||
|
||||
#ifndef NDEBUG
|
||||
void LGYFB_dbgDumpFrame(void);
|
||||
#endif
|
|
@ -1,132 +0,0 @@
|
|||
#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];
|
||||
}
|
|
@ -1,136 +0,0 @@
|
|||
#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);
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
#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))
|
|
@ -1,120 +0,0 @@
|
|||
#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))
|
|
@ -1,79 +0,0 @@
|
|||
#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);
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
/*
|
||||
* This file is part of fastboot 3DS
|
||||
* Copyright (C) 2017 derrek, profi200
|
||||
* 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
|
||||
|
@ -19,8 +17,9 @@
|
|||
*/
|
||||
|
||||
#include "types.h"
|
||||
#include "kernel.h"
|
||||
|
||||
|
||||
|
||||
noreturn void _start(void);
|
||||
void deinitCpu(void);
|
||||
KHandle OAF_videoInit(void);
|
||||
void OAF_videoExit(void);
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
/*
|
||||
* This file is part of fastboot 3DS
|
||||
* Copyright (C) 2020 derrek, profi200
|
||||
* 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
|
||||
|
@ -18,10 +18,21 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "types.h"
|
||||
#include "error_codes.h"
|
||||
|
||||
|
||||
|
||||
Result fsQuickRead(void *const buf, const char *const path, u32 size);
|
||||
Result fsQuickWrite(void *const buf, const char *const path, u32 size);
|
||||
#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
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
/*
|
||||
* This file is part of fastboot 3DS
|
||||
* Copyright (C) 2018 derrek, profi200
|
||||
* This file is part of open_agb_firm
|
||||
* Copyright (C) 2022 spitzeqc
|
||||
*
|
||||
* 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,15 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "types.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
//void WEAK __systemInit(void);
|
||||
void WEAK __systemDeinit(void);
|
||||
Result patchRom(const char *const gamePath, u32 *romSize);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
|
@ -1,24 +0,0 @@
|
|||
#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);
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
/*
|
||||
* This file is part of fastboot 3DS
|
||||
* Copyright (C) 2017 derrek, profi200
|
||||
* This file is part of open_agb_firm
|
||||
* Copyright (C) 2023 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,29 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "types.h"
|
||||
#include "arm11/config.h"
|
||||
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define fb_assert(c) ((void)0)
|
||||
#else
|
||||
#define fb_assert(c) ((c) ? ((void)0) : __fb_assert(#c ", " __FILE__, __LINE__))
|
||||
#ifdef __cplusplus
|
||||
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!");
|
||||
|
||||
|
||||
noreturn void __fb_assert(const char *const str, u32 line);
|
||||
|
||||
u16 detectSaveType(const u32 romSize, const u16 defaultSave);
|
||||
u16 getSaveType(const OafConfig *const cfg, const u32 romSize, const char *const savePath);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
|
@ -1,45 +0,0 @@
|
|||
#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");
|
||||
}
|
|
@ -1,149 +0,0 @@
|
|||
/**
|
||||
* @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
|
|
@ -1,9 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
|
||||
|
||||
extern const u32 _arm7_stub_start[];
|
||||
extern const u32 _arm7_stub_swi[]; // Final ARM9 mem location.
|
||||
extern const u32 _arm7_stub_size[];
|
|
@ -1,29 +0,0 @@
|
|||
#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))
|
|
@ -1,338 +0,0 @@
|
|||
#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);
|
|
@ -1,34 +0,0 @@
|
|||
#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);
|
|
@ -1,99 +0,0 @@
|
|||
#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
|
|
@ -1,189 +0,0 @@
|
|||
#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);
|
|
@ -1,183 +0,0 @@
|
|||
#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
|
|
@ -1,96 +0,0 @@
|
|||
#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))
|
|
@ -1,94 +0,0 @@
|
|||
#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);
|
|
@ -1,54 +0,0 @@
|
|||
#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_INVALID_ARG = 2u,
|
||||
RES_OUT_OF_MEM = 3u,
|
||||
|
||||
// fatfs errors.
|
||||
// Caution: Update fres2Res() in fs.c on ARM9 if this changes!
|
||||
RES_FR_DISK_ERR = 4u, /* (1) A hard error occurred in the low level disk I/O layer */
|
||||
RES_FR_INT_ERR = 5u, /* (2) Assertion failed */
|
||||
RES_FR_NOT_READY = 6u, /* (3) The physical drive cannot work */
|
||||
RES_FR_NO_FILE = 7u, /* (4) Could not find the file */
|
||||
RES_FR_NO_PATH = 8u, /* (5) Could not find the path */
|
||||
RES_FR_INVALID_NAME = 9u, /* (6) The path name format is invalid */
|
||||
RES_FR_DENIED = 10u, /* (7) Access denied due to prohibited access or directory full */
|
||||
RES_FR_EXIST = 11u, /* (8) Access denied due to prohibited access */
|
||||
RES_FR_INVALID_OBJECT = 12u, /* (9) The file/directory object is invalid */
|
||||
RES_FR_WRITE_PROTECTED = 13u, /* (10) The physical drive is write protected */
|
||||
RES_FR_INVALID_DRIVE = 14u, /* (11) The logical drive number is invalid */
|
||||
RES_FR_NOT_ENABLED = 15u, /* (12) The volume has no work area */
|
||||
RES_FR_NO_FILESYSTEM = 16u, /* (13) There is no valid FAT volume */
|
||||
RES_FR_MKFS_ABORTED = 17u, /* (14) The f_mkfs() aborted due to any problem */
|
||||
RES_FR_TIMEOUT = 18u, /* (15) Could not get a grant to access the volume within defined period */
|
||||
RES_FR_LOCKED = 19u, /* (16) The operation is rejected according to the file sharing policy */
|
||||
RES_FR_NOT_ENOUGH_CORE = 20u, /* (17) LFN working buffer could not be allocated */
|
||||
RES_FR_TOO_MANY_OPEN_FILES = 21u, /* (18) Number of open files > FF_FS_LOCK */
|
||||
RES_FR_INVALID_PARAMETER = 22u, /* (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
|
67
include/fs.h
67
include/fs.h
|
@ -1,67 +0,0 @@
|
|||
#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"
|
||||
#ifdef ARM11
|
||||
#include "../thirdparty/fatfs/ff.h"
|
||||
#else
|
||||
#include "fatfs/ff.h"
|
||||
#endif // ifdef ARM11
|
||||
|
||||
|
||||
#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 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
|
|
@ -1,32 +0,0 @@
|
|||
#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);
|
|
@ -1,152 +0,0 @@
|
|||
#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
|
|
@ -1,126 +0,0 @@
|
|||
#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
|
|
@ -1,116 +0,0 @@
|
|||
#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_setGbaRtc(const GbaRtc rtc);
|
||||
Result LGY_getGbaRtc(GbaRtc *const out);
|
||||
Result LGY_backupGbaSave(void);
|
||||
#ifdef ARM11
|
||||
Result LGY_prepareGbaMode(bool biosIntro, char *const romPath);
|
||||
void LGY_switchMode(void);
|
||||
void LGY_handleEvents(void);
|
||||
void LGY_deinit(void);
|
||||
#elif ARM9
|
||||
Result LGY_prepareGbaMode(bool biosIntro, u16 saveType, const char *const savePath);
|
||||
#endif
|
|
@ -1,73 +0,0 @@
|
|||
#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!
|
|
@ -1,91 +0,0 @@
|
|||
#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_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)
|
||||
} 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);
|
|
@ -1,153 +0,0 @@
|
|||
#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
|
|
@ -1,28 +0,0 @@
|
|||
#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);
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
/*
|
||||
* This file is part of fastboot 3DS
|
||||
* Copyright (C) 2017 derrek, profi200
|
||||
* This file is part of open_agb_firm
|
||||
* Copyright (C) 2022 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,29 +18,36 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !__ASSEMBLER__
|
||||
#error Only include this in assembly files!
|
||||
#include "error_codes.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#define MAKE_CUSTOM_ERR(e) (CUSTOM_ERR_OFFSET + (e))
|
||||
|
||||
.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
|
||||
// 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),
|
||||
|
||||
.macro END_ASM_FUNC
|
||||
.cfi_endproc
|
||||
.endfunc
|
||||
.endm
|
||||
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"
|
||||
#endif
|
|
@ -1,76 +0,0 @@
|
|||
#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 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;
|
|
@ -1,48 +0,0 @@
|
|||
#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)
|
||||
|
||||
|
||||
|
||||
NAKED void wait(u32 cycles);
|
||||
|
||||
// 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);
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
Subproject commit ed4525140dacc54e5924f60b25a00c69371866a0
|
|
@ -0,0 +1 @@
|
|||
Subproject commit f6717f66858634b677ed695ee346a89db7684b43
|
Binary file not shown.
|
@ -1,48 +0,0 @@
|
|||
#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);
|
||||
}
|
|
@ -1,154 +0,0 @@
|
|||
#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;
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
#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();
|
||||
};
|
|
@ -1,95 +0,0 @@
|
|||
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();
|
||||
}
|
|
@ -0,0 +1,323 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
|
@ -1,800 +0,0 @@
|
|||
/*
|
||||
* 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 = ¤tCopy;
|
||||
|
||||
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", ¶meter, &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", ¶meter, &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", ¶meter, &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", ¶meter, &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", ¶meter, &consumed);
|
||||
} else {
|
||||
fb_sscanf(escapeseq,"%dm%n", ¶meter, &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 = ¤tConsole->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 = ¤tConsole->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 = ¤tConsole->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 = ¤tConsole->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 = ¤tConsole->frameBuffer[((startx + i) * 240) + (239 - (y + 7))];
|
||||
*screen = color;
|
||||
screen = ¤tConsole->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];
|
||||
}
|
|
@ -1,154 +0,0 @@
|
|||
/*
|
||||
* 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include "types.h"
|
||||
#include "mem_map.h"
|
||||
#include "arm11/console.h"
|
||||
#include "arm11/fmt.h"
|
||||
#include "hardware/pxi.h"
|
||||
#include "ipc_handler.h"
|
||||
#include "hardware/gfx.h"
|
||||
#include "arm11/hardware/interrupt.h"
|
||||
#include "arm.h"
|
||||
#include "arm11/hardware/mcu.h"
|
||||
#include "arm11/hardware/hid.h"
|
||||
|
||||
|
||||
|
||||
noreturn void panic()
|
||||
{
|
||||
enterCriticalSection();
|
||||
|
||||
consoleInit(SCREEN_BOT, NULL);
|
||||
ee_printf("\x1b[41m\x1b[0J\x1b[15C****PANIC!!!****\n");
|
||||
|
||||
//PXI_sendPanicCmd(IPC_CMD9_PANIC);
|
||||
|
||||
// Wait for A/B/X or Y
|
||||
do
|
||||
{
|
||||
hidScanInput();
|
||||
} while(!(hidKeysDown() & (KEY_A | KEY_B | KEY_X | KEY_Y)));
|
||||
|
||||
MCU_powerOffSys();
|
||||
while(1) __wfi();
|
||||
}
|
||||
|
||||
noreturn void panicMsg(const char *msg)
|
||||
{
|
||||
enterCriticalSection();
|
||||
|
||||
consoleInit(SCREEN_BOT, NULL);
|
||||
ee_printf("\x1b[41m\x1b[0J\x1b[15C****PANIC!!!****\n\n");
|
||||
ee_printf("\nERROR MESSAGE:\n%s\n", msg);
|
||||
|
||||
//PXI_sendPanicCmd(IPC_CMD9_PANIC);
|
||||
|
||||
// Wait for A/B/X or Y
|
||||
do
|
||||
{
|
||||
hidScanInput();
|
||||
} while(!(hidKeysDown() & (KEY_A | KEY_B | KEY_X | KEY_Y)));
|
||||
|
||||
MCU_powerOffSys();
|
||||
while(1) __wfi();
|
||||
}
|
||||
|
||||
// Expects the registers in the exception stack to be in the following order:
|
||||
// r0-r14, pc (unmodified), cpsr
|
||||
noreturn void guruMeditation(u8 type, const u32 *excStack)
|
||||
{
|
||||
const char *const typeStr[3] = {"Undefined instruction", "Prefetch abort", "Data abort"};
|
||||
u32 realPc, instSize = 4;
|
||||
//bool codeChanged = false;
|
||||
|
||||
|
||||
// verify text and rodata
|
||||
/*u32 prevHash = debugHash;
|
||||
debugHashCodeRoData();
|
||||
if(prevHash != debugHash)
|
||||
codeChanged = true;*/
|
||||
|
||||
consoleInit(SCREEN_BOT, NULL);
|
||||
|
||||
if(excStack[16] & 0x20) instSize = 2; // Processor was in Thumb mode?
|
||||
if(type == 2) realPc = excStack[15] - (instSize * 2); // Data abort
|
||||
else realPc = excStack[15] - instSize; // Other
|
||||
|
||||
ee_printf("\x1b[41m\x1b[0J\x1b[15CGuru Meditation Error!\n\n%s:\n", typeStr[type]);
|
||||
ee_printf("CPSR: 0x%08" PRIX32 "\n"
|
||||
"r0 = 0x%08" PRIX32 " r6 = 0x%08" PRIX32 " r12 = 0x%08" PRIX32 "\n"
|
||||
"r1 = 0x%08" PRIX32 " r7 = 0x%08" PRIX32 " sp = 0x%08" PRIX32 "\n"
|
||||
"r2 = 0x%08" PRIX32 " r8 = 0x%08" PRIX32 " lr = 0x%08" PRIX32 "\n"
|
||||
"r3 = 0x%08" PRIX32 " r9 = 0x%08" PRIX32 " pc = 0x%08" PRIX32 "\n"
|
||||
"r4 = 0x%08" PRIX32 " r10 = 0x%08" PRIX32 "\n"
|
||||
"r5 = 0x%08" PRIX32 " r11 = 0x%08" PRIX32 "\n\n",
|
||||
excStack[16],
|
||||
excStack[0], excStack[6], excStack[12],
|
||||
excStack[1], excStack[7], excStack[13],
|
||||
excStack[2], excStack[8], excStack[14],
|
||||
excStack[3], excStack[9], realPc,
|
||||
excStack[4], excStack[10],
|
||||
excStack[5], excStack[11]);
|
||||
|
||||
ee_puts("Stack dump:");
|
||||
u32 sp = excStack[13];
|
||||
if(sp >= AXIWRAM_BASE && sp < AXIWRAM_BASE + AXIWRAM_SIZE && !(sp & 3u))
|
||||
{
|
||||
u32 stackWords = ((AXIWRAM_BASE + AXIWRAM_SIZE - sp) / 4 > 48 ? 48 : (AXIWRAM_BASE + AXIWRAM_SIZE - sp) / 4);
|
||||
|
||||
u32 newlineCounter = 0;
|
||||
for(u32 i = 0; i < stackWords; i++)
|
||||
{
|
||||
if(newlineCounter == 4) {ee_printf("\n"); newlineCounter = 0;}
|
||||
ee_printf("0x%08" PRIX32 " ", ((u32*)sp)[i]);
|
||||
newlineCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
//if(codeChanged) ee_printf("Attention: RO section data changed!!");
|
||||
|
||||
//PXI_sendPanicCmd(IPC_CMD9_EXCEPTION);
|
||||
|
||||
// Wait for A/B/X or Y
|
||||
do
|
||||
{
|
||||
hidScanInput();
|
||||
} while(!(hidKeysDown() & (KEY_A | KEY_B | KEY_X | KEY_Y)));
|
||||
|
||||
MCU_powerOffSys();
|
||||
while(1) __wfi();
|
||||
}
|
||||
|
||||
/*void debugMemdump(const char *filepath, void *mem, size_t size)
|
||||
{
|
||||
s32 file;
|
||||
|
||||
if((file = fOpen(filepath, FS_CREATE_ALWAYS | FS_OPEN_WRITE)) < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
fWrite(file, mem, size);
|
||||
|
||||
fSync(file);
|
||||
|
||||
fClose(file);
|
||||
}*/
|
|
@ -0,0 +1,312 @@
|
|||
@ 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 "asm_macros.h"
|
||||
#include "mem_map.h"
|
||||
|
||||
.syntax unified
|
||||
.cpu mpcore
|
||||
.fpu vfpv2
|
||||
|
||||
|
||||
|
||||
@ Whole frame converter.
|
||||
/*BEGIN_ASM_FUNC convertFrameFast
|
||||
@ Load frame, output and lookup table pointers.
|
||||
@ Our frame is in a 512x512 texture. Same for the output.
|
||||
@ The table is a 15 to 32-bit 3D lookup table with color correction pre-applied.
|
||||
ldr r0, =0x18200000 @ r0 = 0x18200000;
|
||||
ldr r1, =0x18300000 @ r1 = 0x18300000;
|
||||
ldr r2, =0x1FF00000 @ r2 = 0x1FF00000;
|
||||
|
||||
@ Prefetch first cache line, save registers, load color mask and load 8 line counter.
|
||||
pld [r0] @ Prefetch from r0.
|
||||
stmfd sp!, {r4-r11, lr} @ Save registers.
|
||||
ldrh r12, =0x7FFF @ r12 = 0x7FFF;
|
||||
mov r11, #30 @ r11 = 30;
|
||||
|
||||
@ Convert 8 lines each round until we have a whole frame.
|
||||
convertFrameFast_8l_lp:
|
||||
@ Load size of 8 lines in bytes.
|
||||
mov r3, #0x1680 @ r3 = 0x1680;
|
||||
|
||||
@ Convert 8 pixels each round until we have 8 lines.
|
||||
convertFrameFast_8p_lp:
|
||||
@ Load 8 pixels from frame.
|
||||
ldmia r0!, {r8-r10, lr} @ r8_to_r10_lr = *((_16BytesBlock*)r0); r0 += 16;
|
||||
|
||||
@ Decrement size and extract first 2 pixels.
|
||||
subs r3, r3, #16 @ r3 -= 16; // Updates flags.
|
||||
and r4, r12, r8, lsr #1 @ r4 = 0x7FFF & (r8>>1); // r12 is 0x7FFF.
|
||||
lsr r5, r8, #17 @ r5 = r8>>17;
|
||||
|
||||
@ Look up pixel 1 and extract pixel 3.
|
||||
ldr r4, [r2, r4, lsl #2] @ r4 = r2[r4]; // u32.
|
||||
and r6, r12, r9, lsr #1 @ r6 = 0x7FFF & (r9>>1); // r12 is 0x7FFF.
|
||||
|
||||
@ Look up pixel 2 and extract pixel 4.
|
||||
ldr r5, [r2, r5, lsl #2] @ r5 = r2[r5]; // u32.
|
||||
lsr r7, r9, #17 @ r7 = r9>>17;
|
||||
|
||||
@ Look up pixel 3 and extract pixel 5.
|
||||
ldr r6, [r2, r6, lsl #2] @ r6 = r2[r6]; // u32.
|
||||
and r8, r12, r10, lsr #1 @ r8 = 0x7FFF & (r10>>1); // r12 is 0x7FFF.
|
||||
|
||||
@ Look up pixel 4 and extract pixel 6.
|
||||
ldr r7, [r2, r7, lsl #2] @ r7 = r2[r7]; // u32.
|
||||
lsr r9, r10, #17 @ r9 = r10>>17;
|
||||
|
||||
@ Look up pixel 5 and extract pixel 7.
|
||||
ldr r8, [r2, r8, lsl #2] @ r8 = r2[r8]; // u32.
|
||||
and r10, r12, lr, lsr #1 @ r10 = 0x7FFF & (lr>>1); // r12 is 0x7FFF.
|
||||
|
||||
@ Look up pixel 6 and extract pixel 8.
|
||||
ldr r9, [r2, r9, lsl #2] @ r9 = r2[r9]; // u32.
|
||||
lsr lr, lr, #17 @ lr = lr>>17;
|
||||
|
||||
@ Look up pixel 7 and 8.
|
||||
ldr r10, [r2, r10, lsl #2] @ r10 = r2[r10]; // u32.
|
||||
ldr lr, [r2, lr, lsl #2] @ lr = r2[lr]; // u32.
|
||||
|
||||
@ Prefetch next cache line, write 8 pixels and jump back if we are not done yet.
|
||||
pld [r0, #32] @ Prefetch from r0 + 32. // Offset 32 is a tiny bit better. Most of the time the result is the same as 64.
|
||||
stmia r1!, {r4-r10, lr} @ *((_32BytesBlock*)r1) = r4_to_r10_lr; r1 += 32;
|
||||
bne convertFrameFast_8p_lp @ if(r3 != 0) goto convertFrameFast_8p_lp;
|
||||
|
||||
@ Decrement 8 line counter, skip texture padding and jump back if we are not done yet.
|
||||
subs r11, r11, #1 @ r11--; // Updates flags.
|
||||
add r0, r0, #0x980 @ r0 += 0x980;
|
||||
add r1, r1, #0x1300 @ r1 += 0x1300;
|
||||
bne convertFrameFast_8l_lp @ if(r11 != 0) goto convertFrameFast_8l_lp;
|
||||
|
||||
ldmfd sp!, {r4-r11, pc} @ Restore registers and return.
|
||||
END_ASM_FUNC*/
|
||||
|
||||
@ Converts a 160p frame while it's being DMAd to memory.
|
||||
BEGIN_ASM_FUNC convert160pFrameFast
|
||||
@ Enable top LCD LgyCap IRQs.
|
||||
mov r0, #77 @ r0 = 77; // id IRQ_LGYCAP_TOP.
|
||||
mov r1, #0 @ r1 = 0; // prio 0 (highest).
|
||||
mov r2, #0 @ r2 = 0; // target 0 (this CPU).
|
||||
mov r3, #0 @ r3 = 0; // isr NULL.
|
||||
blx IRQ_registerIsr @ IRQ_registerIsr(IRQ_LGYCAP_TOP, 0, 0, (IrqIsr)NULL);
|
||||
|
||||
@ We will be using IRQs without our IRQ handler to minimize latency.
|
||||
cpsid i @ __disableIrq();
|
||||
|
||||
@ Load lookup table address and color mask.
|
||||
ldr r2, =0x1FF00000 @ r2 = 0x1FF00000;
|
||||
ldrh r12, =0x7FFF @ r12 = 0x7FFF;
|
||||
|
||||
convert160pFrameFast_frame_lp:
|
||||
@ Load input and output addresses.
|
||||
ldr r0, =0x18200000 @ r0 = 0x18200000; // u32.
|
||||
@ldr r1, =0x18300000 @ r1 = 0x18300000; // u32.
|
||||
add r1, r0, #0x100000 @ r1 = r0 + 0x100000; // Note: ldr would be faster here (result latency). Saves 4 bytes.
|
||||
|
||||
@ Convert 8 lines each round until we have a whole frame.
|
||||
convert160pFrameFast_8l_lp:
|
||||
ldr r4, =0x10111008 @ r4 = ®_LGYCAP1_STAT; // u32.
|
||||
ldr r5, =MPCORE_PRIV_BASE @ r5 = MPCORE_PRIV_BASE; // u32.
|
||||
|
||||
convert160pFrameFast_wait_irq:
|
||||
@ Wait for LgyCap IRQs.
|
||||
wfi @ __waitForInterrupt();
|
||||
|
||||
@ Acknowledge IRQ and extract line number.
|
||||
ldr r11, [r4] @ r11 = REG_LGYCAP_STAT; // u32.
|
||||
ldr r7, [r5, #0x10C] @ r7 = REG_GICC_INTACK; // u32.
|
||||
str r11, [r4] @ REG_LGYCAP_STAT = r11; // u32.
|
||||
lsrs r11, r11, #16 @ r11 >>= 16; // Updates flags.
|
||||
str r7, [r5, #0x110] @ REG_GICC_EOI = r7; // u32.
|
||||
|
||||
@ Ignore DREQ IRQ for line 0.
|
||||
beq convert160pFrameFast_wait_irq @ if((r11>>16) == 0) goto convert160pFrameFast_wait_irq;
|
||||
|
||||
convert160pFrameFast_skip_irq_wait:
|
||||
@ Load size of 8 lines in bytes.
|
||||
mov r3, #0xF00 @ r3 = 0xF00;
|
||||
|
||||
@ Convert 8 pixels each round until we have 8 lines.
|
||||
convert160pFrameFast_8p_lp:
|
||||
@ Load 8 pixels from frame.
|
||||
ldmia r0!, {r8-r10, lr} @ r8_to_r10_lr = *((_16BytesBlock*)r0); r0 += 16;
|
||||
|
||||
@ Decrement size and extract first 2 pixels.
|
||||
subs r3, r3, #16 @ r3 -= 16; // Updates flags.
|
||||
and r4, r12, r8, lsr #1 @ r4 = 0x7FFF & (r8>>1); // r12 is 0x7FFF.
|
||||
lsr r5, r8, #17 @ r5 = r8>>17;
|
||||
|
||||
@ Look up pixel 1 and extract pixel 3.
|
||||
ldr r4, [r2, r4, lsl #2] @ r4 = r2[r4]; // u32.
|
||||
and r6, r12, r9, lsr #1 @ r6 = 0x7FFF & (r9>>1); // r12 is 0x7FFF.
|
||||
|
||||
@ Look up pixel 2 and extract pixel 4.
|
||||
ldr r5, [r2, r5, lsl #2] @ r5 = r2[r5]; // u32.
|
||||
lsr r7, r9, #17 @ r7 = r9>>17;
|
||||
|
||||
@ Look up pixel 3 and extract pixel 5.
|
||||
ldr r6, [r2, r6, lsl #2] @ r6 = r2[r6]; // u32.
|
||||
and r8, r12, r10, lsr #1 @ r8 = 0x7FFF & (r10>>1); // r12 is 0x7FFF.
|
||||
|
||||
@ Look up pixel 4 and extract pixel 6.
|
||||
ldr r7, [r2, r7, lsl #2] @ r7 = r2[r7]; // u32.
|
||||
lsr r9, r10, #17 @ r9 = r10>>17;
|
||||
|
||||
@ Look up pixel 5 and extract pixel 7.
|
||||
ldr r8, [r2, r8, lsl #2] @ r8 = r2[r8]; // u32.
|
||||
and r10, r12, lr, lsr #1 @ r10 = 0x7FFF & (lr>>1); // r12 is 0x7FFF.
|
||||
|
||||
@ Look up pixel 6 and extract pixel 8.
|
||||
ldr r9, [r2, r9, lsl #2] @ r9 = r2[r9]; // u32.
|
||||
lsr lr, lr, #17 @ lr = lr>>17;
|
||||
|
||||
@ Look up pixel 7 and 8.
|
||||
ldr r10, [r2, r10, lsl #2] @ r10 = r2[r10]; // u32.
|
||||
ldr lr, [r2, lr, lsl #2] @ lr = r2[lr]; // u32.
|
||||
|
||||
@ Prefetch next cache line, write 8 pixels and jump back if we are not done yet.
|
||||
pld [r0, #32] @ Prefetch from r0 + 32. // Offset 32 is a tiny bit better. Most of the time the result is the same as 64.
|
||||
stmia r1!, {r4-r10, lr} @ *((_32BytesBlock*)r1) = r4_to_r10_lr; r1 += 32;
|
||||
bne convert160pFrameFast_8p_lp @ if(r3 != 0) goto convert160pFrameFast_8p_lp;
|
||||
|
||||
@ Test if 8 line counter is 152, skip texture padding and jump back if we are not done yet.
|
||||
cmp r11, #152 @ r11 - 152; // Updates flags.
|
||||
add r0, r0, #0x1100 @ r0 += 0x1100;
|
||||
add r1, r1, #0x2200 @ r1 += 0x2200;
|
||||
moveq r11, #160 @ if(r11 == 152) r11 = 160;
|
||||
beq convert160pFrameFast_skip_irq_wait @ if(r11 == 152) goto convert160pFrameFast_skip_irq_wait;
|
||||
bls convert160pFrameFast_8l_lp @ if(r11 <= 152) goto convert160pFrameFast_8l_lp;
|
||||
|
||||
@ Flush the D-Cache, wait for flush completion, notify core 0 and jump back.
|
||||
@ Note: r3 has been decremented down to 0 previously and so it's safe to use.
|
||||
mcr p15, 0, r3, c7, c14, 0 @ Clean and Invalidate Entire Data Cache.
|
||||
ldr r4, =MPCORE_PRIV_BASE @ r4 = MPCORE_PRIV_BASE; // u32.
|
||||
mov r5, #0x10000 @ r5 = 0x10000;
|
||||
orr r5, r5, #0xF @ r5 |= 0xF;
|
||||
add r4, r4, #0x1F00 @ r4 += 0x1F00; // REG_GICD_SOFTINT.
|
||||
mcr p15, 0, r3, c7, c10, 4 @ Data Synchronization Barrier.
|
||||
str r5, [r4] @ *r4 = r5; // u32.
|
||||
b convert160pFrameFast_frame_lp @ goto convert160pFrameFast_frame_lp;
|
||||
END_ASM_FUNC
|
||||
|
||||
@ Converts the frame while it's being DMAd to memory.
|
||||
BEGIN_ASM_FUNC convert240pFrameFast
|
||||
@ Enable top LCD LgyCap IRQs.
|
||||
mov r0, #77 @ r0 = 77; // id IRQ_LGYCAP_TOP.
|
||||
mov r1, #0 @ r1 = 0; // prio 0 (highest).
|
||||
mov r2, #0 @ r2 = 0; // target 0 (this CPU).
|
||||
mov r3, #0 @ r3 = 0; // isr NULL.
|
||||
blx IRQ_registerIsr @ IRQ_registerIsr(IRQ_LGYCAP_TOP, 0, 0, (IrqIsr)NULL);
|
||||
|
||||
@ We will be using IRQs without our IRQ handler to minimize latency.
|
||||
cpsid i @ __disableIrq();
|
||||
|
||||
@ Load lookup table address and color mask.
|
||||
ldr r2, =0x1FF00000 @ r2 = 0x1FF00000;
|
||||
ldrh r12, =0x7FFF @ r12 = 0x7FFF;
|
||||
|
||||
convert240pFrameFast_frame_lp:
|
||||
@ Load input and output addresses.
|
||||
ldr r0, =0x18200000 @ r0 = 0x18200000; // u32.
|
||||
@ldr r1, =0x18300000 @ r1 = 0x18300000; // u32.
|
||||
add r1, r0, #0x100000 @ r1 = r0 + 0x100000; // Note: ldr would be faster here (result latency). Saves 4 bytes.
|
||||
|
||||
@ Convert 8 lines each round until we have a whole frame.
|
||||
convert240pFrameFast_8l_lp:
|
||||
ldr r4, =0x10111008 @ r4 = ®_LGYCAP1_STAT; // u32.
|
||||
ldr r5, =MPCORE_PRIV_BASE @ r5 = MPCORE_PRIV_BASE; // u32.
|
||||
|
||||
convert240pFrameFast_wait_irq:
|
||||
@ Wait for LgyCap IRQs.
|
||||
wfi @ __waitForInterrupt();
|
||||
|
||||
@ Acknowledge IRQ and extract line number.
|
||||
ldr r11, [r4] @ r11 = REG_LGYCAP_STAT; // u32.
|
||||
ldr r7, [r5, #0x10C] @ r7 = REG_GICC_INTACK; // u32.
|
||||
str r11, [r4] @ REG_LGYCAP_STAT = r11; // u32.
|
||||
lsrs r11, r11, #16 @ r11 >>= 16; // Updates flags.
|
||||
str r7, [r5, #0x110] @ REG_GICC_EOI = r7; // u32.
|
||||
|
||||
@ Ignore DREQ IRQ for line 0.
|
||||
beq convert240pFrameFast_wait_irq @ if((r11>>16) == 0) goto convert240pFrameFast_wait_irq;
|
||||
|
||||
convert240pFrameFast_skip_irq_wait:
|
||||
@ Load size of 8 lines in bytes.
|
||||
mov r3, #0x1680 @ r3 = 0x1680;
|
||||
|
||||
@ Convert 8 pixels each round until we have 8 lines.
|
||||
convert240pFrameFast_8p_lp:
|
||||
@ Load 8 pixels from frame.
|
||||
ldmia r0!, {r8-r10, lr} @ r8_to_r10_lr = *((_16BytesBlock*)r0); r0 += 16;
|
||||
|
||||
@ Decrement size and extract first 2 pixels.
|
||||
subs r3, r3, #16 @ r3 -= 16; // Updates flags.
|
||||
and r4, r12, r8, lsr #1 @ r4 = 0x7FFF & (r8>>1); // r12 is 0x7FFF.
|
||||
lsr r5, r8, #17 @ r5 = r8>>17;
|
||||
|
||||
@ Look up pixel 1 and extract pixel 3.
|
||||
ldr r4, [r2, r4, lsl #2] @ r4 = r2[r4]; // u32.
|
||||
and r6, r12, r9, lsr #1 @ r6 = 0x7FFF & (r9>>1); // r12 is 0x7FFF.
|
||||
|
||||
@ Look up pixel 2 and extract pixel 4.
|
||||
ldr r5, [r2, r5, lsl #2] @ r5 = r2[r5]; // u32.
|
||||
lsr r7, r9, #17 @ r7 = r9>>17;
|
||||
|
||||
@ Look up pixel 3 and extract pixel 5.
|
||||
ldr r6, [r2, r6, lsl #2] @ r6 = r2[r6]; // u32.
|
||||
and r8, r12, r10, lsr #1 @ r8 = 0x7FFF & (r10>>1); // r12 is 0x7FFF.
|
||||
|
||||
@ Look up pixel 4 and extract pixel 6.
|
||||
ldr r7, [r2, r7, lsl #2] @ r7 = r2[r7]; // u32.
|
||||
lsr r9, r10, #17 @ r9 = r10>>17;
|
||||
|
||||
@ Look up pixel 5 and extract pixel 7.
|
||||
ldr r8, [r2, r8, lsl #2] @ r8 = r2[r8]; // u32.
|
||||
and r10, r12, lr, lsr #1 @ r10 = 0x7FFF & (lr>>1); // r12 is 0x7FFF.
|
||||
|
||||
@ Look up pixel 6 and extract pixel 8.
|
||||
ldr r9, [r2, r9, lsl #2] @ r9 = r2[r9]; // u32.
|
||||
lsr lr, lr, #17 @ lr = lr>>17;
|
||||
|
||||
@ Look up pixel 7 and 8.
|
||||
ldr r10, [r2, r10, lsl #2] @ r10 = r2[r10]; // u32.
|
||||
ldr lr, [r2, lr, lsl #2] @ lr = r2[lr]; // u32.
|
||||
|
||||
@ Prefetch next cache line, write 8 pixels and jump back if we are not done yet.
|
||||
pld [r0, #32] @ Prefetch from r0 + 32. // Offset 32 is a tiny bit better. Most of the time the result is the same as 64.
|
||||
stmia r1!, {r4-r10, lr} @ *((_32BytesBlock*)r1) = r4_to_r10_lr; r1 += 32;
|
||||
bne convert240pFrameFast_8p_lp @ if(r3 != 0) goto convert240pFrameFast_8p_lp;
|
||||
|
||||
@ Test if 8 line counter is 232, skip texture padding and jump back if we are not done yet.
|
||||
cmp r11, #232 @ r11 - 232; // Updates flags.
|
||||
add r0, r0, #0x980 @ r0 += 0x980;
|
||||
add r1, r1, #0x1300 @ r1 += 0x1300;
|
||||
moveq r11, #240 @ if(r11 == 232) r11 = 240;
|
||||
beq convert240pFrameFast_skip_irq_wait @ if(r11 == 232) goto convert240pFrameFast_skip_irq_wait;
|
||||
bls convert240pFrameFast_8l_lp @ if(r11 <= 232) goto convert240pFrameFast_8l_lp;
|
||||
|
||||
@ Flush the D-Cache, wait for flush completion, notify core 0 and jump back.
|
||||
@ Note: r3 has been decremented down to 0 previously and so it's safe to use.
|
||||
mcr p15, 0, r3, c7, c14, 0 @ Clean and Invalidate Entire Data Cache.
|
||||
ldr r4, =MPCORE_PRIV_BASE @ r4 = MPCORE_PRIV_BASE; // u32.
|
||||
mov r5, #0x10000 @ r5 = 0x10000;
|
||||
orr r5, r5, #0xF @ r5 |= 0xF;
|
||||
add r4, r4, #0x1F00 @ r4 += 0x1F00; // REG_GICD_SOFTINT.
|
||||
mcr p15, 0, r3, c7, c10, 4 @ Data Synchronization Barrier.
|
||||
str r5, [r4] @ *r4 = r5; // u32.
|
||||
b convert240pFrameFast_frame_lp @ goto convert240pFrameFast_frame_lp;
|
||||
END_ASM_FUNC
|
|
@ -0,0 +1,60 @@
|
|||
@ 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 "asm_macros.h"
|
||||
|
||||
.syntax unified
|
||||
.cpu mpcore
|
||||
.fpu vfpv2
|
||||
|
||||
|
||||
|
||||
@ void makeOpenBusPaddingFast(u32 *romEnd);
|
||||
BEGIN_ASM_FUNC makeOpenBusPaddingFast
|
||||
@ Save registers and calculate size from start and highest ROM address.
|
||||
stmfd sp!, {r4, lr} @ Save registers.
|
||||
rsb r1, r0, #0x22000000 @ r1 = 0x22000000 - r0;
|
||||
|
||||
@ Generate pattern halves from address.
|
||||
lsr r2, r0, #1 @ r2 = r0>>1;
|
||||
add r3, r2, #1 @ r3 = r2 + 1;
|
||||
|
||||
@ Generate constant for incrementing the pattern halves.
|
||||
mov r12, #2 @ r12 = 2;
|
||||
add r12, r12, #0x20000 @ r12 += 0x20000;
|
||||
|
||||
@ Join pattern halves and precalculate the next 3 patterns.
|
||||
pkhbt r2, r2, r3, lsl #16 @ r2 = (r2 & 0xFFFF) | r3<<16;
|
||||
uadd16 r3, r2, r12 @ r3 = ((r2 + 0x20000) & 0xFFFF0000) | ((r2 + 2) & 0xFFFF); // r12 is 0x20002.
|
||||
uadd16 r4, r3, r12 @ r4 = ((r3 + 0x20000) & 0xFFFF0000) | ((r3 + 2) & 0xFFFF); // r12 is 0x20002.
|
||||
uadd16 lr, r4, r12 @ lr = ((r4 + 0x20000) & 0xFFFF0000) | ((r4 + 2) & 0xFFFF); // r12 is 0x20002.
|
||||
|
||||
@ Adjust constant for unrolled loop. 0x20002 --> 0x80008.
|
||||
lsl r12, r12, #2 @ r12 <<= 2;
|
||||
makeOpenBusPaddingFast_blk_lp:
|
||||
@ Store 16 pattern bytes at a time and decrement size.
|
||||
stmia r0!, {r2-r4, lr} @ *((_16BytesBlock*)r0) = r2_to_r4_lr; r0 += 16;
|
||||
subs r1, r1, #16 @ r1 -= 16; // Updates flags.
|
||||
|
||||
@ Increment patterns and jump back if we are not done yet.
|
||||
uadd16 r2, r2, r12 @ r2 = ((r2 + 0x80000) & 0xFFFF0000) | ((r2 + 8) & 0xFFFF); // r12 is 0x80008.
|
||||
uadd16 r3, r3, r12 @ r3 = ((r3 + 0x80000) & 0xFFFF0000) | ((r3 + 8) & 0xFFFF); // r12 is 0x80008.
|
||||
uadd16 r4, r4, r12 @ r3 = ((r4 + 0x80000) & 0xFFFF0000) | ((r4 + 8) & 0xFFFF); // r12 is 0x80008.
|
||||
uadd16 lr, lr, r12 @ lr = ((lr + 0x80000) & 0xFFFF0000) | ((lr + 8) & 0xFFFF); // r12 is 0x80008.
|
||||
bne makeOpenBusPaddingFast_blk_lp @ if(r1 != 0) goto makeOpenBusPaddingFast_blk_lp;
|
||||
|
||||
ldmfd sp!, {r4, pc} @ Restore registers and return.
|
||||
END_ASM_FUNC
|
|
@ -1,49 +1,75 @@
|
|||
/*
|
||||
* 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "types.h"
|
||||
#include "error_codes.h"
|
||||
#include "fs.h"
|
||||
#include "arm11/hardware/hid.h"
|
||||
#include "util.h"
|
||||
#include "arm11/drivers/hid.h"
|
||||
#include "arm11/fmt.h"
|
||||
#include "hardware/gfx.h"
|
||||
#include "drivers/gfx.h"
|
||||
|
||||
|
||||
#define MAX_DIR_ENTRIES (510u)
|
||||
#define DIR_READ_BLOCKS (10u)
|
||||
#define SCREEN_COLS (53u - 1) // - 1 because the console inserts a newline after the last line otherwise.
|
||||
#define SCREEN_ROWS (24u)
|
||||
// Notes on these settings:
|
||||
// MAX_ENT_BUF_SIZE should be big enough to hold the average file/dir name length * MAX_DIR_ENTRIES.
|
||||
#define MAX_ENT_BUF_SIZE (1024u * 196) // 196 KiB.
|
||||
#define MAX_DIR_ENTRIES (1000u)
|
||||
#define DIR_READ_BLOCKS (10u)
|
||||
#define SCREEN_COLS (53u - 1) // - 1 because the console inserts a newline after the last line otherwise.
|
||||
#define SCREEN_ROWS (24u)
|
||||
|
||||
#define ENT_TYPE_FILE (0)
|
||||
#define ENT_TYPE_DIR (1)
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 num;
|
||||
const char *strPtrs[MAX_DIR_ENTRIES];
|
||||
u8 entTypes[MAX_DIR_ENTRIES]; // 0 = file, 1 = dir
|
||||
char strBufs[MAX_DIR_ENTRIES][256];
|
||||
u32 num; // Total number of entries.
|
||||
char entBuf[MAX_ENT_BUF_SIZE]; // Format: char entryType; char name[X]; // null terminated.
|
||||
char *ptrs[MAX_DIR_ENTRIES]; // For fast sorting.
|
||||
} DirList;
|
||||
|
||||
|
||||
|
||||
// num including null terminator.
|
||||
static size_t safeStrcpy(char *const dst, const char *const src, size_t num)
|
||||
int dlistCompare(const void *a, const void *b)
|
||||
{
|
||||
if(num == 0) return 0;
|
||||
const char *entA = *(char**)a;
|
||||
const char *entB = *(char**)b;
|
||||
|
||||
const size_t len = strlen(src) + 1;
|
||||
if(len > num)
|
||||
// Compare the entry type. Dirs have priority over files.
|
||||
if(*entA != *entB) return (int)*entB - *entA;
|
||||
|
||||
// Compare the string.
|
||||
int res;
|
||||
do
|
||||
{
|
||||
*dst = '\0';
|
||||
return 1;
|
||||
}
|
||||
res = *++entA - *++entB;
|
||||
} while(res == 0 && *entA != '\0' && *entB != '\0');
|
||||
|
||||
strcpy(dst, src);
|
||||
return len;
|
||||
return res;
|
||||
}
|
||||
|
||||
static Result scanDir(const char *const path, DirList *const dList, const char *const filter)
|
||||
{
|
||||
FILINFO *const fi = (FILINFO*)malloc(sizeof(FILINFO) * DIR_READ_BLOCKS);
|
||||
if(fi == NULL) return RES_OUT_OF_MEM;
|
||||
FILINFO *const fis = (FILINFO*)malloc(sizeof(FILINFO) * DIR_READ_BLOCKS);
|
||||
if(fis == NULL) return RES_OUT_OF_MEM;
|
||||
|
||||
dList->num = 0;
|
||||
|
||||
|
@ -51,39 +77,46 @@ static Result scanDir(const char *const path, DirList *const dList, const char *
|
|||
DHandle dh;
|
||||
if((res = fOpenDir(&dh, path)) == RES_OK)
|
||||
{
|
||||
u32 read;
|
||||
u32 dListPos = 0;
|
||||
u32 read; // Number of entries read by fReadDir().
|
||||
u32 numEntries = 0; // Total number of processed entries.
|
||||
u32 entBufPos = 0; // Entry buffer position/number of bytes used.
|
||||
const u32 filterLen = strlen(filter);
|
||||
do
|
||||
{
|
||||
if((res = fReadDir(dh, fi, DIR_READ_BLOCKS, &read)) != RES_OK) break;
|
||||
if(dListPos + read > MAX_DIR_ENTRIES) break;
|
||||
if((res = fReadDir(dh, fis, DIR_READ_BLOCKS, &read)) != RES_OK) break;
|
||||
read = (read <= MAX_DIR_ENTRIES - numEntries ? read : MAX_DIR_ENTRIES - numEntries);
|
||||
|
||||
for(u32 i = 0; i < read; i++)
|
||||
{
|
||||
const u8 isDir = (fi[i].fattrib & AM_DIR ? 1u : 0u);
|
||||
if(isDir == 0) // File
|
||||
const char entType = (fis[i].fattrib & AM_DIR ? ENT_TYPE_DIR : ENT_TYPE_FILE);
|
||||
const u32 nameLen = strlen(fis[i].fname);
|
||||
if(entType == ENT_TYPE_FILE)
|
||||
{
|
||||
const u32 entLen = strlen(fi[i].fname);
|
||||
if(entLen <= filterLen || strcmp(filter, fi[i].fname + entLen - filterLen) != 0)
|
||||
if(nameLen <= filterLen || strcmp(filter, fis[i].fname + nameLen - filterLen) != 0
|
||||
|| fis[i].fname[0] == '.')
|
||||
continue;
|
||||
}
|
||||
|
||||
dList->strPtrs[dListPos] = dList->strBufs[dListPos];
|
||||
dList->entTypes[dListPos] = isDir;
|
||||
safeStrcpy(dList->strBufs[dListPos], fi[i].fname, 256);
|
||||
dListPos++;
|
||||
// nameLen does not include the entry type and NULL termination.
|
||||
if(entBufPos + nameLen + 2 > MAX_ENT_BUF_SIZE) goto scanEnd;
|
||||
|
||||
char *const entry = &dList->entBuf[entBufPos];
|
||||
*entry = entType;
|
||||
safeStrcpy(&entry[1], fis[i].fname, 256);
|
||||
dList->ptrs[numEntries++] = entry;
|
||||
entBufPos += nameLen + 2;
|
||||
}
|
||||
} while(read == DIR_READ_BLOCKS);
|
||||
dList->num = dListPos;
|
||||
|
||||
scanEnd:
|
||||
dList->num = numEntries;
|
||||
|
||||
fCloseDir(dh);
|
||||
}
|
||||
|
||||
free(fi);
|
||||
free(fis);
|
||||
|
||||
// Hacky casting of function pointers. But they are compatible.
|
||||
qsort(dList->strPtrs, dList->num, sizeof(char*), (int (*)(const void *, const void *))strcmp);
|
||||
qsort(dList->ptrs, dList->num, sizeof(char*), dlistCompare);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -97,9 +130,9 @@ static void showDirList(const DirList *const dList, u32 start)
|
|||
for(u32 i = start; i < listLength; i++)
|
||||
{
|
||||
const char *const printStr =
|
||||
(dList->entTypes[i] == 0 ? "\x1b[%lu;H\x1b[37m %.51s" : "\x1b[%lu;H\x1b[33m %.51s");
|
||||
(*dList->ptrs[i] == ENT_TYPE_FILE ? "\x1b[%lu;H\x1b[37;1m %.52s" : "\x1b[%lu;H\x1b[33;1m %.52s");
|
||||
|
||||
ee_printf(printStr, i - start, dList->strPtrs[i]);
|
||||
ee_printf(printStr, i - start + 1, &dList->ptrs[i][1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,8 +157,9 @@ Result browseFiles(const char *const basePath, char selected[512])
|
|||
s32 oldCursorPos = 0;
|
||||
while(1)
|
||||
{
|
||||
ee_printf("\x1b[%lu;H ", oldCursorPos - windowPos); // Clear old cursor.
|
||||
ee_printf("\x1b[%lu;H\x1b[37m>", cursorPos - windowPos); // Draw cursor.
|
||||
ee_printf("\x1b[%lu;H ", oldCursorPos - windowPos + 1); // Clear old cursor.
|
||||
ee_printf("\x1b[%lu;H\x1b[37m>", cursorPos - windowPos + 1); // Draw cursor.
|
||||
GFX_flushBuffers();
|
||||
|
||||
u32 kDown;
|
||||
do
|
||||
|
@ -137,13 +171,14 @@ Result browseFiles(const char *const basePath, char selected[512])
|
|||
kDown = hidKeysDown();
|
||||
} while(kDown == 0);
|
||||
|
||||
if(dList->num != 0)
|
||||
const u32 num = dList->num;
|
||||
if(num != 0)
|
||||
{
|
||||
oldCursorPos = cursorPos;
|
||||
if(kDown & KEY_DRIGHT)
|
||||
{
|
||||
cursorPos += SCREEN_ROWS;
|
||||
if((u32)cursorPos > dList->num) cursorPos = dList->num - 1;
|
||||
if((u32)cursorPos > num) cursorPos = num - 1;
|
||||
}
|
||||
if(kDown & KEY_DLEFT)
|
||||
{
|
||||
|
@ -154,8 +189,8 @@ Result browseFiles(const char *const basePath, char selected[512])
|
|||
if(kDown & KEY_DDOWN) cursorPos += 1;
|
||||
}
|
||||
|
||||
if(cursorPos < 0) cursorPos = dList->num - 1; // Wrap to end of list.
|
||||
if((u32)cursorPos > (dList->num - 1)) cursorPos = 0; // Wrap to start of list.
|
||||
if(cursorPos < 0) cursorPos = num - 1; // Wrap to end of list.
|
||||
if((u32)cursorPos > (num - 1)) cursorPos = 0; // Wrap to start of list.
|
||||
|
||||
if((u32)cursorPos < windowPos)
|
||||
{
|
||||
|
@ -172,13 +207,13 @@ Result browseFiles(const char *const basePath, char selected[512])
|
|||
{
|
||||
u32 pathLen = strlen(curDir);
|
||||
|
||||
if(kDown & KEY_A && dList->num != 0)
|
||||
if(kDown & KEY_A && num != 0)
|
||||
{
|
||||
// TODO: !!! Insecure !!!
|
||||
if(curDir[pathLen - 1] != '/') curDir[pathLen++] = '/';
|
||||
safeStrcpy(curDir + pathLen, dList->strPtrs[cursorPos], 256);
|
||||
safeStrcpy(curDir + pathLen, &dList->ptrs[cursorPos][1], 256);
|
||||
|
||||
if(dList->entTypes[cursorPos] == 0)
|
||||
if(*dList->ptrs[cursorPos] == ENT_TYPE_FILE)
|
||||
{
|
||||
safeStrcpy(selected, curDir, 512);
|
||||
break;
|
||||
|
@ -207,4 +242,4 @@ end:
|
|||
ee_printf("\x1b[2J");
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
|
@ -1,421 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* File : barebones/ee_printf.c
|
||||
This file contains an implementation of ee_printf that only requires a method to output a char to a UART without pulling in library code.
|
||||
|
||||
This code is based on a file that contains the following:
|
||||
Copyright (C) 2002 Michael Ringgaard. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the project nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
//TuxSH's changes: add support for 64-bit numbers, remove floating-point code
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include "types.h"
|
||||
#include "arm11/fmt.h"
|
||||
#include "arm11/console.h"
|
||||
|
||||
#define ZEROPAD (1<<0) //Pad with zero
|
||||
#define SIGN (1<<1) //Unsigned/signed long
|
||||
#define PLUS (1<<2) //Show plus
|
||||
#define SPACE (1<<3) //Spacer
|
||||
#define LEFT (1<<4) //Left justified
|
||||
#define HEX_PREP (1<<5) //0x
|
||||
#define UPPERCASE (1<<6) //'ABCDEF'
|
||||
|
||||
#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
|
||||
|
||||
static s32 skipAtoi(const char **s)
|
||||
{
|
||||
s32 i = 0;
|
||||
|
||||
while(IS_DIGIT(**s)) i = i * 10 + *((*s)++) - '0';
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static char *processNumber(char *str, const char *const strEnd, s64 num, bool isHex, s32 size, s32 precision, u32 type)
|
||||
{
|
||||
char sign = 0;
|
||||
|
||||
if(type & SIGN)
|
||||
{
|
||||
if(num < 0)
|
||||
{
|
||||
sign = '-';
|
||||
num = -num;
|
||||
size--;
|
||||
}
|
||||
else if(type & PLUS)
|
||||
{
|
||||
sign = '+';
|
||||
size--;
|
||||
}
|
||||
else if(type & SPACE)
|
||||
{
|
||||
sign = ' ';
|
||||
size--;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *lowerDigits = "0123456789abcdef",
|
||||
*upperDigits = "0123456789ABCDEF";
|
||||
|
||||
s32 i = 0;
|
||||
char tmp[20];
|
||||
const char *dig = (type & UPPERCASE) ? upperDigits : lowerDigits;
|
||||
|
||||
if(num == 0)
|
||||
{
|
||||
if(precision != 0) tmp[i++] = '0';
|
||||
type &= ~HEX_PREP;
|
||||
}
|
||||
else
|
||||
{
|
||||
while(num != 0)
|
||||
{
|
||||
u64 base = isHex ? 16ULL : 10ULL;
|
||||
tmp[i++] = dig[(u64)num % base];
|
||||
num = (s64)((u64)num / base);
|
||||
}
|
||||
}
|
||||
|
||||
if(type & LEFT || precision != -1) type &= ~ZEROPAD;
|
||||
if(type & HEX_PREP && isHex) size -= 2;
|
||||
if(i > precision) precision = i;
|
||||
size -= precision;
|
||||
if(!(type & (ZEROPAD | LEFT)))
|
||||
while(size-- > 0)
|
||||
{
|
||||
if(str >= strEnd) goto end;
|
||||
*str++ = ' ';
|
||||
}
|
||||
if(sign)
|
||||
{
|
||||
if(str >= strEnd) goto end;
|
||||
*str++ = sign;
|
||||
}
|
||||
|
||||
if(type & HEX_PREP && isHex)
|
||||
{
|
||||
if(str + 2 >= strEnd) goto end;
|
||||
*str++ = '0';
|
||||
*str++ = 'x';
|
||||
}
|
||||
|
||||
if(type & ZEROPAD)
|
||||
while(size-- > 0)
|
||||
{
|
||||
if(str >= strEnd) goto end;
|
||||
*str++ = '0';
|
||||
}
|
||||
while(i < precision--)
|
||||
{
|
||||
if(str >= strEnd) goto end;
|
||||
*str++ = '0';
|
||||
}
|
||||
while(i-- > 0)
|
||||
{
|
||||
if(str >= strEnd) goto end;
|
||||
*str++ = tmp[i];
|
||||
}
|
||||
while(size-- > 0)
|
||||
{
|
||||
if(str >= strEnd) goto end;
|
||||
*str++ = ' ';
|
||||
}
|
||||
|
||||
end:
|
||||
return str;
|
||||
}
|
||||
|
||||
u32 ee_vsnprintf(char *buf, u32 size, const char *fmt, va_list args)
|
||||
{
|
||||
if(size == 0) return 0;
|
||||
const char *const strEnd = buf + size - 1;
|
||||
|
||||
char *str;
|
||||
for(str = buf; *fmt; fmt++)
|
||||
{
|
||||
if(*fmt != '%')
|
||||
{
|
||||
if(str >= strEnd) break;
|
||||
*str++ = *fmt;
|
||||
continue;
|
||||
}
|
||||
|
||||
//Process flags
|
||||
u32 flags = 0; //Flags to number()
|
||||
bool loop = true;
|
||||
|
||||
while(loop)
|
||||
{
|
||||
switch(*++fmt)
|
||||
{
|
||||
case '-': flags |= LEFT; break;
|
||||
case '+': flags |= PLUS; break;
|
||||
case ' ': flags |= SPACE; break;
|
||||
case '#': flags |= HEX_PREP; break;
|
||||
case '0': flags |= ZEROPAD; break;
|
||||
default: loop = false; break;
|
||||
}
|
||||
}
|
||||
|
||||
//Get field width
|
||||
s32 fieldWidth = -1; //Width of output field
|
||||
if(IS_DIGIT(*fmt)) fieldWidth = skipAtoi(&fmt);
|
||||
else if(*fmt == '*')
|
||||
{
|
||||
fmt++;
|
||||
|
||||
fieldWidth = va_arg(args, s32);
|
||||
|
||||
if(fieldWidth < 0)
|
||||
{
|
||||
fieldWidth = -fieldWidth;
|
||||
flags |= LEFT;
|
||||
}
|
||||
}
|
||||
|
||||
//Get the precision
|
||||
s32 precision = -1; //Min. # of digits for integers; max number of chars for from string
|
||||
if(*fmt == '.')
|
||||
{
|
||||
fmt++;
|
||||
|
||||
if(IS_DIGIT(*fmt)) precision = skipAtoi(&fmt);
|
||||
else if(*fmt == '*')
|
||||
{
|
||||
fmt++;
|
||||
precision = va_arg(args, s32);
|
||||
}
|
||||
|
||||
if(precision < 0) precision = 0;
|
||||
}
|
||||
|
||||
//Get the conversion qualifier
|
||||
u32 integerType = 0;
|
||||
if(*fmt == 'l')
|
||||
{
|
||||
if(*++fmt == 'l')
|
||||
{
|
||||
fmt++;
|
||||
integerType = 1;
|
||||
}
|
||||
|
||||
}
|
||||
else if(*fmt == 'h')
|
||||
{
|
||||
if(*++fmt == 'h')
|
||||
{
|
||||
fmt++;
|
||||
integerType = 3;
|
||||
}
|
||||
else integerType = 2;
|
||||
}
|
||||
|
||||
bool isHex;
|
||||
|
||||
switch(*fmt)
|
||||
{
|
||||
case 'c':
|
||||
if(!(flags & LEFT))
|
||||
while(--fieldWidth > 0)
|
||||
{
|
||||
if(str >= strEnd) goto end;
|
||||
*str++ = ' ';
|
||||
}
|
||||
if(str >= strEnd) goto end;
|
||||
*str++ = (u8)va_arg(args, s32);
|
||||
while(--fieldWidth > 0)
|
||||
{
|
||||
if(str >= strEnd) goto end;
|
||||
*str++ = ' ';
|
||||
}
|
||||
continue;
|
||||
|
||||
case 's':
|
||||
{
|
||||
char *s = va_arg(args, char *);
|
||||
if(!s) s = "<NULL>";
|
||||
u32 len = (precision != -1) ? strnlen(s, precision) : strlen(s);
|
||||
if(!(flags & LEFT))
|
||||
while((s32)len < fieldWidth--)
|
||||
{
|
||||
if(str >= strEnd) goto end;
|
||||
*str++ = ' ';
|
||||
}
|
||||
for(u32 i = 0; i < len; i++)
|
||||
{
|
||||
if(str >= strEnd) goto end;
|
||||
*str++ = *s++;
|
||||
}
|
||||
while((s32)len < fieldWidth--)
|
||||
{
|
||||
if(str >= strEnd) goto end;
|
||||
*str++ = ' ';
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
case 'p':
|
||||
if(fieldWidth == -1)
|
||||
{
|
||||
fieldWidth = 8;
|
||||
flags |= ZEROPAD;
|
||||
}
|
||||
str = processNumber(str, strEnd, va_arg(args, u32), true, fieldWidth, precision, flags);
|
||||
continue;
|
||||
|
||||
//Integer number formats - set up the flags and "break"
|
||||
case 'X':
|
||||
flags |= UPPERCASE;
|
||||
//Falls through
|
||||
case 'x':
|
||||
isHex = true;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
case 'i':
|
||||
flags |= SIGN;
|
||||
//Falls through
|
||||
case 'u':
|
||||
isHex = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
if(*fmt != '%')
|
||||
{
|
||||
if(str >= strEnd) goto end;
|
||||
*str++ = '%';
|
||||
}
|
||||
if(*fmt)
|
||||
{
|
||||
if(str >= strEnd) goto end;
|
||||
*str++ = *fmt;
|
||||
}
|
||||
else fmt--;
|
||||
continue;
|
||||
}
|
||||
|
||||
s64 num;
|
||||
|
||||
if(flags & SIGN)
|
||||
{
|
||||
if(integerType == 1) num = va_arg(args, s64);
|
||||
else num = va_arg(args, s32);
|
||||
|
||||
if(integerType == 2) num = (s16)num;
|
||||
else if(integerType == 3) num = (s8)num;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(integerType == 1) num = va_arg(args, u64);
|
||||
else num = va_arg(args, u32);
|
||||
|
||||
if(integerType == 2) num = (u16)num;
|
||||
else if(integerType == 3) num = (u8)num;
|
||||
}
|
||||
|
||||
str = processNumber(str, strEnd, num, isHex, fieldWidth, precision, flags);
|
||||
}
|
||||
|
||||
end:
|
||||
*str = 0;
|
||||
return str - buf;
|
||||
}
|
||||
|
||||
u32 ee_vsprintf(char *const buf, const char *const fmt, va_list arg)
|
||||
{
|
||||
return ee_vsnprintf(buf, 0x1000, fmt, arg);
|
||||
}
|
||||
|
||||
__attribute__ ((format (printf, 2, 3))) u32 ee_sprintf(char *const buf, const char *const fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
u32 res = ee_vsnprintf(buf, 0x1000, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
__attribute__ ((format (printf, 3, 4))) u32 ee_snprintf(char *const buf, u32 size, const char *const fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
u32 res = ee_vsnprintf(buf, size, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
__attribute__ ((format (printf, 1, 2))) u32 ee_printf(const char *const fmt, ...)
|
||||
{
|
||||
char buf[512];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
u32 res = ee_vsnprintf(buf, 512, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
con_write(NULL, NULL, buf, res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
u32 ee_puts(const char *const str)
|
||||
{
|
||||
con_write(NULL, NULL, str, strnlen(str, 512));
|
||||
con_write(NULL, NULL, "\n", 1);
|
||||
return 0;
|
||||
}
|
|
@ -1,187 +0,0 @@
|
|||
/*
|
||||
* 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 <string.h>
|
||||
#include "types.h"
|
||||
#include "error_codes.h"
|
||||
#include "fs.h"
|
||||
#include "ipc_handler.h"
|
||||
#include "hardware/pxi.h"
|
||||
|
||||
|
||||
|
||||
Result fMount(FsDrive drive)
|
||||
{
|
||||
const u32 cmdBuf = drive;
|
||||
return PXI_sendCmd(IPC_CMD9_FMOUNT, &cmdBuf, 1);
|
||||
}
|
||||
|
||||
Result fUnmount(FsDrive drive)
|
||||
{
|
||||
const u32 cmdBuf = drive;
|
||||
return PXI_sendCmd(IPC_CMD9_FUNMOUNT, &cmdBuf, 1);
|
||||
}
|
||||
|
||||
Result fGetFree(FsDrive drive, u64 *const size)
|
||||
{
|
||||
u32 cmdBuf[3];
|
||||
cmdBuf[0] = (u32)size;
|
||||
cmdBuf[1] = sizeof(u64);
|
||||
cmdBuf[2] = drive;
|
||||
|
||||
return PXI_sendCmd(IPC_CMD9_FGETFREE, cmdBuf, 3);
|
||||
}
|
||||
|
||||
Result fOpen(FHandle *const hOut, const char *const path, u8 mode)
|
||||
{
|
||||
u32 cmdBuf[5];
|
||||
cmdBuf[0] = (u32)path;
|
||||
cmdBuf[1] = strlen(path) + 1;
|
||||
cmdBuf[2] = (u32)hOut;
|
||||
cmdBuf[3] = sizeof(FHandle);
|
||||
cmdBuf[4] = mode;
|
||||
|
||||
return PXI_sendCmd(IPC_CMD9_FOPEN, cmdBuf, 5);
|
||||
}
|
||||
|
||||
Result fRead(FHandle h, void *const buf, u32 size, u32 *const bytesRead)
|
||||
{
|
||||
u32 cmdBuf[5];
|
||||
cmdBuf[0] = (u32)buf;
|
||||
cmdBuf[1] = size;
|
||||
cmdBuf[2] = (u32)bytesRead;
|
||||
cmdBuf[3] = sizeof(u32);
|
||||
cmdBuf[4] = h;
|
||||
|
||||
return PXI_sendCmd(IPC_CMD9_FREAD, cmdBuf, 5);
|
||||
}
|
||||
|
||||
Result fWrite(FHandle h, const void *const buf, u32 size, u32 *const bytesWritten)
|
||||
{
|
||||
u32 cmdBuf[5];
|
||||
cmdBuf[0] = (u32)buf;
|
||||
cmdBuf[1] = size;
|
||||
cmdBuf[2] = (u32)bytesWritten;
|
||||
cmdBuf[3] = sizeof(u32);
|
||||
cmdBuf[4] = h;
|
||||
|
||||
return PXI_sendCmd(IPC_CMD9_FWRITE, cmdBuf, 5);
|
||||
}
|
||||
|
||||
Result fSync(FHandle h)
|
||||
{
|
||||
const u32 cmdBuf = h;
|
||||
return PXI_sendCmd(IPC_CMD9_FSYNC, &cmdBuf, 1);
|
||||
}
|
||||
|
||||
Result fLseek(FHandle h, u32 off)
|
||||
{
|
||||
u32 cmdBuf[2];
|
||||
cmdBuf[0] = h;
|
||||
cmdBuf[1] = off;
|
||||
|
||||
return PXI_sendCmd(IPC_CMD9_FLSEEK, cmdBuf, 2);
|
||||
}
|
||||
|
||||
u32 fTell(FHandle h)
|
||||
{
|
||||
const u32 cmdBuf = h;
|
||||
return PXI_sendCmd(IPC_CMD9_FTELL, &cmdBuf, 1);
|
||||
}
|
||||
|
||||
u32 fSize(FHandle h)
|
||||
{
|
||||
const u32 cmdBuf = h;
|
||||
return PXI_sendCmd(IPC_CMD9_FSIZE, &cmdBuf, 1);
|
||||
}
|
||||
|
||||
Result fClose(FHandle h)
|
||||
{
|
||||
const u32 cmdBuf = h;
|
||||
return PXI_sendCmd(IPC_CMD9_FCLOSE, &cmdBuf, 1);
|
||||
}
|
||||
|
||||
Result fStat(const char *const path, FILINFO *const fi)
|
||||
{
|
||||
u32 cmdBuf[4];
|
||||
cmdBuf[0] = (u32)path;
|
||||
cmdBuf[1] = strlen(path) + 1;
|
||||
cmdBuf[2] = (u32)fi;
|
||||
cmdBuf[3] = sizeof(FILINFO);
|
||||
|
||||
return PXI_sendCmd(IPC_CMD9_FSTAT, cmdBuf, 4);
|
||||
}
|
||||
|
||||
Result fOpenDir(DHandle *const hOut, const char *const path)
|
||||
{
|
||||
u32 cmdBuf[4];
|
||||
cmdBuf[0] = (u32)path;
|
||||
cmdBuf[1] = strlen(path) + 1;
|
||||
cmdBuf[2] = (u32)hOut;
|
||||
cmdBuf[3] = sizeof(DHandle);
|
||||
|
||||
return PXI_sendCmd(IPC_CMD9_FOPEN_DIR, cmdBuf, 4);
|
||||
}
|
||||
|
||||
Result fReadDir(DHandle h, FILINFO *const fi, u32 num, u32 *const entriesRead)
|
||||
{
|
||||
u32 cmdBuf[6];
|
||||
cmdBuf[0] = (u32)fi;
|
||||
cmdBuf[1] = sizeof(FILINFO) * num;
|
||||
cmdBuf[2] = (u32)entriesRead;
|
||||
cmdBuf[3] = sizeof(u32);
|
||||
cmdBuf[4] = h;
|
||||
cmdBuf[5] = num;
|
||||
|
||||
return PXI_sendCmd(IPC_CMD9_FREAD_DIR, cmdBuf, 6);
|
||||
}
|
||||
|
||||
Result fCloseDir(DHandle h)
|
||||
{
|
||||
const u32 cmdBuf = h;
|
||||
return PXI_sendCmd(IPC_CMD9_FCLOSE_DIR, &cmdBuf, 1);
|
||||
}
|
||||
|
||||
Result fMkdir(const char *const path)
|
||||
{
|
||||
u32 cmdBuf[2];
|
||||
cmdBuf[0] = (u32)path;
|
||||
cmdBuf[1] = strlen(path) + 1;
|
||||
|
||||
return PXI_sendCmd(IPC_CMD9_FMKDIR, cmdBuf, 2);
|
||||
}
|
||||
|
||||
Result fRename(const char *const old, const char *const _new)
|
||||
{
|
||||
u32 cmdBuf[4];
|
||||
cmdBuf[0] = (u32)old;
|
||||
cmdBuf[1] = strlen(old) + 1;
|
||||
cmdBuf[2] = (u32)_new;
|
||||
cmdBuf[3] = strlen(_new) + 1;
|
||||
|
||||
return PXI_sendCmd(IPC_CMD9_FRENAME, cmdBuf, 4);
|
||||
}
|
||||
|
||||
Result fUnlink(const char *const path)
|
||||
{
|
||||
u32 cmdBuf[2];
|
||||
cmdBuf[0] = (u32)path;
|
||||
cmdBuf[1] = strlen(path) + 1;
|
||||
|
||||
return PXI_sendCmd(IPC_CMD9_FUNLINK, cmdBuf, 2);
|
||||
}
|
|
@ -0,0 +1,230 @@
|
|||
/*
|
||||
* This file is part of open_agb_firm
|
||||
* Copyright (C) 2022 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 <string.h>
|
||||
#include "types.h"
|
||||
#include "arm11/gpu_cmd_lists.h"
|
||||
#include "drivers/cache.h"
|
||||
|
||||
|
||||
// 360x240 without scaling, no filter.
|
||||
alignas(16) u8 gbaGpuInitList[GBA_INIT_LIST_SIZE] =
|
||||
{
|
||||
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, 0x12, 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, 0x00, 0x00, 0x00, 0x00, // Last 4 bytes: GPUREG_TEXUNIT0_PARAM.
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x02, 0x00, 0x00, 0x00, // Last 4 bytes: GPUREG_TEXUNIT0_TYPE.
|
||||
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,
|
||||
0x89, 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
|
||||
};
|
||||
|
||||
// 360x240 without scaling, no filter.
|
||||
alignas(16) u8 gbaGpuList2[GBA_LIST2_SIZE] =
|
||||
{
|
||||
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, 0x12, 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, 0x89, 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
|
||||
};
|
||||
|
||||
|
||||
|
||||
void patchGbaGpuCmdList(const u8 scaleType, const bool useSecondTexture)
|
||||
{
|
||||
if(useSecondTexture)
|
||||
{
|
||||
u32 tmp = GPU_TEXTURE2_ADDR>>3;
|
||||
memcpy(&gbaGpuInitList[580], &tmp, 4);
|
||||
tmp = 0;
|
||||
memcpy(&gbaGpuInitList[584], &tmp, 4);
|
||||
}
|
||||
|
||||
if(scaleType == 0)
|
||||
{
|
||||
u32 tmp = 0x4440;
|
||||
memcpy(&gbaGpuInitList[952], &tmp, 2);
|
||||
gbaGpuInitList[958] = 0x45;
|
||||
gbaGpuInitList[968] = 0x60;
|
||||
memcpy(&gbaGpuInitList[984], &tmp, 2);
|
||||
gbaGpuInitList[989] = 0x40;
|
||||
gbaGpuInitList[1000] = 0x60;
|
||||
tmp = 0x3DE000;
|
||||
memcpy(&gbaGpuInitList[1004], &tmp, 4);
|
||||
gbaGpuInitList[1016] = 0x90;
|
||||
gbaGpuInitList[1022] = 0x45;
|
||||
gbaGpuInitList[1048] = 0x90;
|
||||
gbaGpuInitList[1053] = 0x40;
|
||||
memcpy(&gbaGpuInitList[1068], &tmp, 4);
|
||||
|
||||
tmp = 0x4440;
|
||||
memcpy(&gbaGpuList2[264], &tmp, 2);
|
||||
gbaGpuList2[270] = 0x45;
|
||||
gbaGpuList2[280] = 0x60;
|
||||
memcpy(&gbaGpuList2[296], &tmp, 2);
|
||||
gbaGpuList2[301] = 0x40;
|
||||
gbaGpuList2[312] = 0x60;
|
||||
tmp = 0x3DE000;
|
||||
memcpy(&gbaGpuList2[316], &tmp, 4);
|
||||
gbaGpuList2[328] = 0x90;
|
||||
gbaGpuList2[334] = 0x45;
|
||||
gbaGpuList2[360] = 0x90;
|
||||
gbaGpuList2[365] = 0x40;
|
||||
memcpy(&gbaGpuList2[380], &tmp, 4);
|
||||
}
|
||||
else if(scaleType == 1)
|
||||
{
|
||||
gbaGpuInitList[572] = 2;
|
||||
gbaGpuInitList[968] = 0x60;
|
||||
gbaGpuInitList[1000] = 0x60;
|
||||
u32 tmp = 0x3DE000;
|
||||
memcpy(&gbaGpuInitList[1004], &tmp, 4);
|
||||
memcpy(&gbaGpuInitList[1068], &tmp, 4);
|
||||
|
||||
gbaGpuList2[280] = 0x60;
|
||||
gbaGpuList2[312] = 0x60;
|
||||
memcpy(&gbaGpuList2[316], &tmp, 4);
|
||||
memcpy(&gbaGpuList2[380], &tmp, 4);
|
||||
}
|
||||
// else nothing to do.
|
||||
|
||||
flushDCacheRange(gbaGpuInitList, sizeof(gbaGpuInitList));
|
||||
flushDCacheRange(gbaGpuList2, sizeof(gbaGpuList2));
|
||||
}
|
|
@ -1,130 +0,0 @@
|
|||
/*
|
||||
* 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 "asm_macros.h"
|
||||
|
||||
.cpu mpcore
|
||||
.fpu vfpv2
|
||||
|
||||
|
||||
#define ICACHE_SIZE (0x4000)
|
||||
#define DCACHE_SIZE (0x4000)
|
||||
#define CACHE_LINE_SIZE (32)
|
||||
|
||||
|
||||
|
||||
BEGIN_ASM_FUNC invalidateICache
|
||||
mov r0, #0
|
||||
mcr p15, 0, r0, c7, c5, 0 @ Invalidate Entire Instruction Cache, also flushes the branch target cache
|
||||
@mcr p15, 0, r0, c7, c5, 6 @ Flush Entire Branch Target Cache
|
||||
mcr p15, 0, r0, c7, c10, 4 @ Data Synchronization Barrier
|
||||
mcr p15, 0, r0, c7, c5, 4 @ Flush Prefetch Buffer
|
||||
bx lr
|
||||
END_ASM_FUNC
|
||||
|
||||
|
||||
BEGIN_ASM_FUNC invalidateICacheRange
|
||||
add r1, r1, r0
|
||||
bic r0, r0, #(CACHE_LINE_SIZE - 1)
|
||||
mov r2, #0
|
||||
invalidateICacheRange_lp:
|
||||
mcr p15, 0, r0, c7, c5, 1 @ Invalidate Instruction Cache Line (using MVA)
|
||||
add r0, r0, #CACHE_LINE_SIZE
|
||||
cmp r0, r1
|
||||
blt invalidateICacheRange_lp
|
||||
mcr p15, 0, r2, c7, c5, 6 @ Flush Entire Branch Target Cache
|
||||
mcr p15, 0, r2, c7, c10, 4 @ Data Synchronization Barrier
|
||||
mcr p15, 0, r2, c7, c5, 4 @ Flush Prefetch Buffer
|
||||
bx lr
|
||||
END_ASM_FUNC
|
||||
|
||||
|
||||
BEGIN_ASM_FUNC cleanDCache
|
||||
mov r0, #0
|
||||
mcr p15, 0, r0, c7, c10, 0 @ Clean Entire Data Cache
|
||||
mcr p15, 0, r0, c7, c10, 4 @ Data Synchronization Barrier
|
||||
bx lr
|
||||
END_ASM_FUNC
|
||||
|
||||
|
||||
BEGIN_ASM_FUNC flushDCache
|
||||
mov r0, #0
|
||||
mcr p15, 0, r0, c7, c14, 0 @ Clean and Invalidate Entire Data Cache
|
||||
mcr p15, 0, r0, c7, c10, 4 @ Data Synchronization Barrier
|
||||
bx lr
|
||||
END_ASM_FUNC
|
||||
|
||||
|
||||
BEGIN_ASM_FUNC cleanDCacheRange
|
||||
cmp r1, #DCACHE_SIZE
|
||||
bhi cleanDCache
|
||||
add r1, r1, r0
|
||||
bic r0, r0, #(CACHE_LINE_SIZE - 1)
|
||||
mov r2, #0
|
||||
cleanDCacheRange_lp:
|
||||
mcr p15, 0, r0, c7, c10, 1 @ Clean Data Cache Line (using MVA)
|
||||
add r0, r0, #CACHE_LINE_SIZE
|
||||
cmp r0, r1
|
||||
blt cleanDCacheRange_lp
|
||||
mcr p15, 0, r2, c7, c10, 4 @ Data Synchronization Barrier
|
||||
bx lr
|
||||
END_ASM_FUNC
|
||||
|
||||
|
||||
BEGIN_ASM_FUNC flushDCacheRange
|
||||
cmp r1, #DCACHE_SIZE
|
||||
bhi flushDCache
|
||||
add r1, r1, r0
|
||||
bic r0, r0, #(CACHE_LINE_SIZE - 1)
|
||||
mov r2, #0
|
||||
flushDCacheRange_lp:
|
||||
mcr p15, 0, r0, c7, c14, 1 @ Clean and Invalidate Data Cache Line (using MVA)
|
||||
add r0, r0, #CACHE_LINE_SIZE
|
||||
cmp r0, r1
|
||||
blt flushDCacheRange_lp
|
||||
mcr p15, 0, r2, c7, c10, 4 @ Data Synchronization Barrier
|
||||
bx lr
|
||||
END_ASM_FUNC
|
||||
|
||||
|
||||
BEGIN_ASM_FUNC invalidateDCache
|
||||
mov r0, #0
|
||||
mcr p15, 0, r0, c7, c6, 0 @ Invalidate Entire Data Cache
|
||||
mcr p15, 0, r0, c7, c10, 4 @ Data Synchronization Barrier
|
||||
bx lr
|
||||
END_ASM_FUNC
|
||||
|
||||
|
||||
BEGIN_ASM_FUNC invalidateDCacheRange
|
||||
cmp r1, #DCACHE_SIZE
|
||||
bhi flushDCache
|
||||
add r1, r1, r0
|
||||
tst r0, #(CACHE_LINE_SIZE - 1)
|
||||
mcrne p15, 0, r0, c7, c10, 1 @ Clean Data Cache Line (using MVA)
|
||||
tst r1, #(CACHE_LINE_SIZE - 1)
|
||||
mcrne p15, 0, r1, c7, c10, 1 @ Clean Data Cache Line (using MVA)
|
||||
bic r0, r0, #(CACHE_LINE_SIZE - 1)
|
||||
mov r2, #0
|
||||
invalidateDCacheRange_lp:
|
||||
mcr p15, 0, r0, c7, c6, 1 @ Invalidate Data Cache Line (using MVA)
|
||||
add r0, r0, #CACHE_LINE_SIZE
|
||||
cmp r0, r1
|
||||
blt invalidateDCacheRange_lp
|
||||
mcr p15, 0, r2, c7, c10, 4 @ Data Synchronization Barrier
|
||||
bx lr
|
||||
END_ASM_FUNC
|
|
@ -1,459 +0,0 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
// Based on code from https://github.com/xerpi/linux_3ds/blob/master/drivers/input/misc/nintendo3ds_codec_hid.c
|
||||
|
||||
#include "types.h"
|
||||
#include "arm11/hardware/codec.h"
|
||||
#include "arm11/hardware/spi.h"
|
||||
#include "arm11/hardware/pdn.h"
|
||||
#include "arm11/hardware/timer.h"
|
||||
#include "arm11/hardware/gpio.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 driverGainHP;
|
||||
u8 driverGainSP;
|
||||
u8 analogVolumeHP;
|
||||
u8 analogVolumeSP;
|
||||
s8 shutterVolume[2];
|
||||
u8 microphoneBias;
|
||||
u8 quickCharge;
|
||||
u8 PGA_GAIN; // microphone gain
|
||||
u8 reserved[3];
|
||||
s16 filterHP32[15]; // 3 * 5
|
||||
s16 filterHP47[15];
|
||||
s16 filterSP32[15];
|
||||
s16 filterSP47[15];
|
||||
s16 filterMic32[28]; // (1+2)+((1+4)*5)
|
||||
s16 filterMic47[28];
|
||||
s16 filterFree[28];
|
||||
u8 analogInterval;
|
||||
u8 analogStabilize;
|
||||
u8 analogPrecharge;
|
||||
u8 analogSense;
|
||||
u8 analogDebounce;
|
||||
u8 analog_XP_Pullup;
|
||||
u8 YM_Driver;
|
||||
u8 reserved2;
|
||||
} CodecCal;
|
||||
|
||||
|
||||
alignas(4) static CodecCal fallbackCal =
|
||||
{
|
||||
0u,
|
||||
1u,
|
||||
0u,
|
||||
7u,
|
||||
{0xFD, 0xEC},
|
||||
3u,
|
||||
2u,
|
||||
0u,
|
||||
{0, 0, 0},
|
||||
{32767, 0, 0, 0, 0, 32767, 0, 0, 0, 0, 32736, 49168, 0, 16352, 0},
|
||||
{32767, 0, 0, 0, 0, 32767, 0, 0, 0, 0, 32745, 49164, 0, 16361, 0},
|
||||
{32767, 38001, 22413, 30870, 36440, 51536, 30000, 51536, 0, 0, 32736, 49168, 0, 16352, 0},
|
||||
{32767, 36541, 25277, 31456, 35336, 51134, 30000, 51134, 0, 0, 32745, 49164, 0, 16361, 0},
|
||||
{32767, 0, 0, 32767, 0, 0, 0, 0, 32767, 0, 0, 0, 0, 32767, 0, 0, 0, 0, 32767, 0, 0, 0, 0, 32767, 0, 0, 0, 0},
|
||||
{32767, 0, 0, 32767, 0, 0, 0, 0, 32767, 0, 0, 0, 0, 32767, 0, 0, 0, 0, 32767, 0, 0, 0, 0, 32767, 0, 0, 0, 0},
|
||||
{32767, 0, 0, 52577, 56751, 32767, 8785, 12959, 52577, 56751, 32767, 8785, 12959, 52577, 56751, 32767, 8785, 12959, 32767, 0, 0, 0, 0, 32767, 0, 0, 0, 0},
|
||||
1u,
|
||||
9u,
|
||||
4u,
|
||||
3u,
|
||||
0u,
|
||||
6u,
|
||||
1u,
|
||||
0u
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void codecSwitchBank(u8 bank)
|
||||
{
|
||||
static u8 curBank = 0x63;
|
||||
if(curBank != bank)
|
||||
{
|
||||
curBank = bank;
|
||||
|
||||
alignas(4) u8 inBuf[4];
|
||||
inBuf[0] = 0; // Write
|
||||
inBuf[1] = bank;
|
||||
NSPI_writeRead(NSPI_DEV_CTR_CODEC, (u32*)inBuf, NULL, 2, 0, true);
|
||||
}
|
||||
}
|
||||
|
||||
static void codecReadRegBuf(u8 bank, u8 reg, u32 *buf, u32 size)
|
||||
{
|
||||
codecSwitchBank(bank);
|
||||
|
||||
alignas(4) u8 inBuf[4];
|
||||
inBuf[0] = reg<<1 | 1u;
|
||||
NSPI_writeRead(NSPI_DEV_CTR_CODEC, (u32*)inBuf, buf, 1, size, true);
|
||||
}
|
||||
|
||||
static u8 codecReadReg(u8 bank, u8 reg)
|
||||
{
|
||||
alignas(4) u8 outBuf[4];
|
||||
codecReadRegBuf(bank, reg, (u32*)outBuf, 1);
|
||||
|
||||
return outBuf[0];
|
||||
}
|
||||
|
||||
static void codecWriteRegBuf(u8 bank, u8 reg, u32 *buf, u32 size)
|
||||
{
|
||||
codecSwitchBank(bank);
|
||||
|
||||
alignas(4) u8 inBuf[4];
|
||||
inBuf[0] = reg<<1; // Write
|
||||
NSPI_writeRead(NSPI_DEV_CTR_CODEC, (u32*)inBuf, NULL, 1, 0, false);
|
||||
NSPI_writeRead(NSPI_DEV_CTR_CODEC, buf, NULL, size, 0, true);
|
||||
}
|
||||
|
||||
static void codecWriteReg(u8 bank, u8 reg, u8 val)
|
||||
{
|
||||
codecSwitchBank(bank);
|
||||
|
||||
alignas(4) u8 inBuf[4];
|
||||
inBuf[0] = reg<<1; // Write
|
||||
inBuf[1] = val;
|
||||
NSPI_writeRead(NSPI_DEV_CTR_CODEC, (u32*)inBuf, NULL, 2, 0, true);
|
||||
}
|
||||
|
||||
static void codecMaskReg(u8 bank, u8 reg, u8 val, u8 mask)
|
||||
{
|
||||
u8 data = codecReadReg(bank, reg);
|
||||
data = (data & ~mask) | (val & mask);
|
||||
codecWriteReg(bank, reg, data);
|
||||
}
|
||||
|
||||
// Helpers
|
||||
static void codecSwapCalibrationData(CodecCal *cal)
|
||||
{
|
||||
u16 *tmp = (u16*)cal->filterHP32;
|
||||
for(int i = 0; i < 15; i++)
|
||||
{
|
||||
tmp[i] = __builtin_bswap16(tmp[i]);
|
||||
}
|
||||
|
||||
tmp = (u16*)cal->filterHP47;
|
||||
for(int i = 0; i < 15; i++)
|
||||
{
|
||||
tmp[i] = __builtin_bswap16(tmp[i]);
|
||||
}
|
||||
|
||||
tmp = (u16*)cal->filterSP32;
|
||||
for(int i = 0; i < 15; i++)
|
||||
{
|
||||
tmp[i] = __builtin_bswap16(tmp[i]);
|
||||
}
|
||||
|
||||
tmp = (u16*)cal->filterSP47;
|
||||
for(int i = 0; i < 15; i++)
|
||||
{
|
||||
tmp[i] = __builtin_bswap16(tmp[i]);
|
||||
}
|
||||
|
||||
tmp = (u16*)cal->filterMic32;
|
||||
for(int i = 0; i < 28; i++)
|
||||
{
|
||||
tmp[i] = __builtin_bswap16(tmp[i]);
|
||||
}
|
||||
|
||||
tmp = (u16*)cal->filterMic47;
|
||||
for(int i = 0; i < 28; i++)
|
||||
{
|
||||
tmp[i] = __builtin_bswap16(tmp[i]);
|
||||
}
|
||||
|
||||
tmp = (u16*)cal->filterFree;
|
||||
for(int i = 0; i < 28; i++)
|
||||
{
|
||||
tmp[i] = __builtin_bswap16(tmp[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void codecMaskWaitReg(u8 bank, u8 reg, u8 val, u8 mask)
|
||||
{
|
||||
for(u32 i = 0; i < 64; i++) // Some kind of timeout? No error checking.
|
||||
{
|
||||
codecMaskReg(bank, reg, val, mask);
|
||||
if((codecReadReg(bank, reg) & mask) == val) break;
|
||||
}
|
||||
}
|
||||
|
||||
static void codecEnableTouchscreen(void)
|
||||
{
|
||||
codecMaskReg(0x67, 0x26, 0x80, 0x80);
|
||||
codecMaskReg(0x67, 0x24, 0, 0x80);
|
||||
codecMaskReg(0x67, 0x25, 0x10, 0x3C);
|
||||
}
|
||||
|
||||
static void codecDisableTouchscreen(void)
|
||||
{
|
||||
codecMaskReg(0x67, 0x26, 0, 0x80);
|
||||
codecMaskReg(0x67, 0x24, 0x80, 0x80);
|
||||
}
|
||||
|
||||
static void codecLegacyStuff(bool enabled)
|
||||
{
|
||||
if(enabled)
|
||||
{
|
||||
*((vu16*)0x10141114) |= 2u;
|
||||
*((vu16*)0x10141116) |= 2u;
|
||||
codecMaskReg(0x67, 0x25, 0x40, 0x40);
|
||||
}
|
||||
else
|
||||
{
|
||||
codecMaskReg(0x67, 0x25, 0, 0x40);
|
||||
*((vu16*)0x10141114) &= ~2u;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CODEC_init(void)
|
||||
{
|
||||
static bool inited = false;
|
||||
if(inited) return;
|
||||
inited = true;
|
||||
|
||||
|
||||
NSPI_init();
|
||||
|
||||
// TODO: Load calibration from HWCAL files on eMMC.
|
||||
CodecCal *const cal = &fallbackCal;
|
||||
codecSwapCalibrationData(cal); // Come the fuck on. Why is this not stored in the correct endianness?
|
||||
|
||||
// General codec reset + init?
|
||||
REG_PDN_I2S_CNT = PDN_I2S_CNT_I2S_CLK2_E;
|
||||
codecWriteReg(0x64, 1, 1);
|
||||
TIMER_sleepMs(40);
|
||||
codecSwitchBank(0); // What? Dummy switch after reset?
|
||||
codecWriteReg(0x64, 0x43, 0x11);
|
||||
codecMaskReg(0x65, 0x77, 1, 1);
|
||||
codecMaskReg(0, 0x39, 0x66, 0x66);
|
||||
codecWriteReg(0x65, 0x7A, 1);
|
||||
codecMaskReg(0x64, 0x22, 0x18, 0x18);
|
||||
GPIO_config(GPIO_2_HEADPH_JACK, GPIO_IRQ_ENABLE | GPIO_EDGE_RISING | GPIO_INPUT); // Headphone jack IRQ.
|
||||
//codecMaskReg(0x64, 0x45, (*((vu8*)0x10147010) & 1u)<<4 | 1u<<5, 0x30); // GPIO bitmask 8.
|
||||
codecMaskReg(0x64, 0x45, 0, 0x30); // With automatic output switching
|
||||
codecMaskReg(0x64, 0x43, 0, 0x80);
|
||||
codecMaskReg(0x64, 0x43, 0x80, 0x80);
|
||||
codecWriteReg(0, 0xB, 0x87);
|
||||
codecMaskReg(0x64, 0x7C, 0, 1);
|
||||
|
||||
// sub_3257FC()
|
||||
codecMaskReg(0x64, 0x22, 0, 4);
|
||||
// In AgbBg this is swapped at runtime.
|
||||
alignas(4) static const u16 unkData1[3] = {0xE17F, 0x1F80, 0xC17F};
|
||||
codecWriteRegBuf(4, 8, (u32*)unkData1, 6);
|
||||
codecWriteRegBuf(5, 8, (u32*)cal->filterMic32, 56);
|
||||
codecWriteRegBuf(5, 0x48, (u32*)cal->filterMic47, 56);
|
||||
codecMaskReg(1, 0x30, 0x40, 0xC0);
|
||||
codecMaskReg(1, 0x31, 0x40, 0xC0);
|
||||
codecWriteReg(0x65, 0x33, cal->microphoneBias);
|
||||
codecMaskWaitReg(0x65, 0x41, cal->PGA_GAIN, 0x3F);
|
||||
codecMaskWaitReg(0x65, 0x42, cal->quickCharge, 3);
|
||||
codecWriteReg(1, 0x2F, 0x2Bu & 0x7Fu);
|
||||
codecMaskReg(0x64, 0x31, 0x44, 0x44); // AgbBg uses val = 0 here
|
||||
codecWriteReg(0, 0x41, cal->shutterVolume[0]);
|
||||
codecWriteReg(0, 0x42, cal->shutterVolume[0]);
|
||||
codecWriteReg(0x64, 0x7B, cal->shutterVolume[1]);
|
||||
|
||||
// Sound stuff starts here
|
||||
// Speaker "depop circuit"? Whatever that is. Not existent on retail?
|
||||
GPIO_config(GPIO_3_0, GPIO_OUTPUT);
|
||||
GPIO_write(GPIO_3_0, 1); // GPIO bitmask 0x40
|
||||
TIMER_sleepMs(10); // Fixed 10 ms delay when setting this GPIO.
|
||||
*((vu16*)0x10145000) = 0xC800u | 0x20u<<6;
|
||||
*((vu16*)0x10145002) = 0xE000u;
|
||||
codecMaskReg(0x65, 0x11, 0x10, 0x1C);
|
||||
codecWriteReg(0x64, 0x7A, 0);
|
||||
codecWriteReg(0x64, 0x78, 0);
|
||||
{ // This code block is missing in AgbBg but present in codec module.
|
||||
const bool flag = (~codecReadReg(0, 0x40) & 0xCu) == 0;
|
||||
codecMaskReg(0, 0x3F, 0, 0xC0);
|
||||
codecWriteReg(0, 0x40, 0xC);
|
||||
for(u32 i = 0; i < 100; i++) // Some kind of timeout? No error checking.
|
||||
{
|
||||
if(!(~codecReadReg(0x64, 0x26) & 0x44u)) break;
|
||||
TIMER_sleepMs(1);
|
||||
}
|
||||
codecWriteRegBuf(9, 2, (u32*)cal->filterFree, 6);
|
||||
codecWriteRegBuf(8, 0xC, (u32*)&cal->filterFree[3], 50);
|
||||
codecWriteRegBuf(9, 8, (u32*)cal->filterFree, 6);
|
||||
codecWriteRegBuf(8, 0x4C, (u32*)&cal->filterFree[3], 50);
|
||||
if(!flag)
|
||||
{
|
||||
codecMaskReg(0, 0x3F, 0xC0, 0xC0);
|
||||
codecWriteReg(0, 0x40, 0);
|
||||
}
|
||||
}
|
||||
{
|
||||
const bool flag = (~codecReadReg(0x64, 0x77) & 0xCu) == 0;
|
||||
codecMaskReg(0x64, 0x77, 0xC, 0xC);
|
||||
for(u32 i = 0; i < 100; i++) // Some kind of timeout? No error checking.
|
||||
{
|
||||
if(!(~codecReadReg(0x64, 0x26) & 0x88u)) break;
|
||||
TIMER_sleepMs(1);
|
||||
}
|
||||
codecWriteRegBuf(0xA, 2, (u32*)cal->filterFree, 6);
|
||||
codecWriteRegBuf(0xA, 0xC, (u32*)&cal->filterFree[3], 50);
|
||||
if(!flag) codecMaskReg(0x64, 0x77, 0, 0xC);
|
||||
}
|
||||
|
||||
codecWriteRegBuf(0xC, 2, (u32*)cal->filterSP32, 30);
|
||||
codecWriteRegBuf(0xC, 0x42, (u32*)cal->filterSP32, 30);
|
||||
codecWriteRegBuf(0xC, 0x20, (u32*)cal->filterSP47, 30);
|
||||
codecWriteRegBuf(0xC, 0x60, (u32*)cal->filterSP47, 30);
|
||||
codecWriteRegBuf(0xB, 2, (u32*)cal->filterHP32, 30);
|
||||
codecWriteRegBuf(0xB, 0x42, (u32*)cal->filterHP32, 30);
|
||||
codecWriteRegBuf(0xB, 0x20, (u32*)cal->filterHP47, 30);
|
||||
codecWriteRegBuf(0xB, 0x60, (u32*)cal->filterHP47, 30);
|
||||
codecMaskReg(0x64, 0x76, 0xC0, 0xC0);
|
||||
TIMER_sleepMs(10);
|
||||
for(u32 i = 0; i < 100; i++) // Some kind of timeout? No error checking.
|
||||
{
|
||||
if(!(~codecReadReg(0x64, 0x25) & 0x88u)) break;
|
||||
TIMER_sleepMs(1);
|
||||
}
|
||||
codecWriteReg(0x65, 0xA, 0xA);
|
||||
|
||||
codecMaskReg(0, 0x3F, 0xC0, 0xC0);
|
||||
codecWriteReg(0, 0x40, 0);
|
||||
codecMaskReg(0x64, 0x77, 0, 0xC);
|
||||
|
||||
u8 val;
|
||||
if((codecReadReg(0, 2) & 0xFu) <= 1u && ((codecReadReg(0, 3) & 0x70u)>>4 <= 2u))
|
||||
{
|
||||
val = 0x3C;
|
||||
}
|
||||
else val = 0x1C;
|
||||
codecWriteReg(0x65, 0xB, val);
|
||||
|
||||
codecWriteReg(0x65, 0xC, (cal->driverGainHP<<3) | 4);
|
||||
codecWriteReg(0x65, 0x16, cal->analogVolumeHP);
|
||||
codecWriteReg(0x65, 0x17, cal->analogVolumeHP);
|
||||
codecMaskReg(0x65, 0x11, 0xC0, 0xC0);
|
||||
codecWriteReg(0x65, 0x12, (cal->driverGainSP<<2) | 2);
|
||||
codecWriteReg(0x65, 0x13, (cal->driverGainSP<<2) | 2);
|
||||
codecWriteReg(0x65, 0x1B, cal->analogVolumeSP);
|
||||
codecWriteReg(0x65, 0x1C, cal->analogVolumeSP);
|
||||
TIMER_sleepMs(38);
|
||||
GPIO_write(GPIO_3_0, 0); // GPIO bitmask 0x40
|
||||
TIMER_sleepMs(18); // Fixed 18 ms delay when unsetting this GPIO.
|
||||
|
||||
|
||||
// Circle pad
|
||||
codecWriteReg(0x67, 0x24, 0x98);
|
||||
codecWriteReg(0x67, 0x26, 0x00);
|
||||
codecWriteReg(0x67, 0x25, 0x43);
|
||||
codecWriteReg(0x67, 0x24, 0x18);
|
||||
codecWriteReg(0x67, 0x17, cal->analogPrecharge<<4 | cal->analogSense);
|
||||
codecWriteReg(0x67, 0x19, cal->analog_XP_Pullup<<4 | cal->analogStabilize);
|
||||
codecWriteReg(0x67, 0x1B, cal->YM_Driver<<7 | cal->analogDebounce);
|
||||
codecWriteReg(0x67, 0x27, 0x10u | cal->analogInterval);
|
||||
codecWriteReg(0x67, 0x26, 0xEC);
|
||||
codecWriteReg(0x67, 0x24, 0x18);
|
||||
codecWriteReg(0x67, 0x25, 0x53);
|
||||
|
||||
// Not needed?
|
||||
//I2C_writeReg(I2C_DEV_CTR_MCU, 0x26, I2C_readReg(I2C_DEV_CTR_MCU, 0x26) | 0x10);
|
||||
|
||||
codecEnableTouchscreen();
|
||||
}
|
||||
|
||||
bool touchscreenState = false;
|
||||
bool legacySwitchState = false;
|
||||
|
||||
void CODEC_deinit(void)
|
||||
{
|
||||
GPIO_write(GPIO_3_0, 1); // GPIO bitmask 0x40
|
||||
TIMER_sleepMs(10); // Fixed 10 ms delay when setting this GPIO.
|
||||
legacySwitchState = (codecReadReg(0x67, 0x25) & 0x40u) != 0;
|
||||
if(!legacySwitchState) codecLegacyStuff(true);
|
||||
codecMaskReg(0x67, 0x25, 0, 3);
|
||||
touchscreenState = (codecReadReg(0x67, 0x24)>>7) == 0;
|
||||
codecDisableTouchscreen();
|
||||
codecMaskReg(0x64, 0x76, 0, 0xC0);
|
||||
TIMER_sleepMs(30);
|
||||
for(u32 i = 0; i < 100; i++)
|
||||
{
|
||||
if(!(codecReadReg(0x64, 0x25) & 0x88u)) break;
|
||||
TIMER_sleepMs(1);
|
||||
}
|
||||
codecMaskReg(0x64, 0x22, 2, 2);
|
||||
TIMER_sleepMs(30);
|
||||
for(u32 i = 0; i < 64; i++)
|
||||
{
|
||||
if(codecReadReg(0x64, 0x22) & 1u) break;
|
||||
TIMER_sleepMs(1);
|
||||
}
|
||||
*((vu16*)0x10145000) &= ~0x8000u;
|
||||
*((vu16*)0x10145002) &= ~0x8000u;
|
||||
REG_PDN_I2S_CNT = 0;
|
||||
GPIO_write(GPIO_3_0, 0); // GPIO bitmask 0x40
|
||||
TIMER_sleepMs(18); // Fixed 18 ms delay when unsetting this GPIO.
|
||||
}
|
||||
|
||||
void CODEC_wakeup(void)
|
||||
{
|
||||
GPIO_write(GPIO_3_0, 1); // GPIO bitmask 0x40
|
||||
TIMER_sleepMs(10); // Fixed 10 ms delay when setting this GPIO.
|
||||
REG_PDN_I2S_CNT = PDN_I2S_CNT_I2S_CLK2_E;
|
||||
*((vu16*)0x10145000) |= 0x8000u;
|
||||
*((vu16*)0x10145002) |= 0x8000u;
|
||||
//codecMaskReg(0x64, 0x45, 0, 0x30); // Output select automatic
|
||||
codecMaskReg(0x64, 0x43, 0, 0x80);
|
||||
codecMaskReg(0x64, 0x43, 0x80, 0x80);
|
||||
codecMaskReg(0x64, 0x22, 0, 2);
|
||||
TIMER_sleepMs(40);
|
||||
for(u32 i = 0; i < 40; i++)
|
||||
{
|
||||
if(!(codecReadReg(0x64, 0x22) & 1u)) break;
|
||||
TIMER_sleepMs(1);
|
||||
}
|
||||
codecMaskReg(0x64, 0x76, 0xC0, 0xC0);
|
||||
TIMER_sleepMs(10);
|
||||
for(u32 i = 0; i < 100; i++)
|
||||
{
|
||||
if(!(~codecReadReg(0x64, 0x25) & 0x88u)) break;
|
||||
TIMER_sleepMs(1);
|
||||
}
|
||||
codecMaskReg(0x67, 0x25, 3, 3);
|
||||
codecLegacyStuff(legacySwitchState);
|
||||
if(touchscreenState) codecEnableTouchscreen();
|
||||
GPIO_write(GPIO_3_0, 0); // GPIO bitmask 0x40
|
||||
TIMER_sleepMs(18); // Fixed 18 ms delay when unsetting this GPIO.
|
||||
}
|
||||
|
||||
bool CODEC_getRawAdcData(CdcAdcData *data)
|
||||
{
|
||||
if((codecReadReg(0x67, 0x26) & 2u) == 0)
|
||||
{
|
||||
codecReadRegBuf(0xFB, 1, (u32*)data, sizeof(CdcAdcData));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Codec module does this when data is unavailable. Why?
|
||||
//codecSwitchBank(0);
|
||||
|
||||
return false;
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
* 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"
|
||||
#include "arm11/hardware/csnd.h"
|
||||
#include "arm11/hardware/codec.h"
|
||||
|
||||
|
||||
|
||||
void CSND_init(void)
|
||||
{
|
||||
static bool inited = false;
|
||||
if(inited) return;
|
||||
inited = true;
|
||||
|
||||
|
||||
CODEC_init();
|
||||
|
||||
//static const u8 sliderBounds[2] = {0xE, 0xF6}; // Volume slider 0% and 100% offset
|
||||
//I2C_writeRegBuf(I2C_DEV_CTR_MCU, 0x58, sliderBounds, 2);
|
||||
REG_CSND_MASTER_VOL = 0x8000;
|
||||
REG_CSND_UNK_CNT = 1u<<15 | 1u<<14;
|
||||
|
||||
for(u32 i = 0; i < 32; i++) REG_CSND_CH_CNT(i) = 0;
|
||||
for(u32 i = 0; i < 2; i++) REG_CSND_CAP_CNT(i) = 0;
|
||||
}
|
||||
|
||||
void CSND_setupCh(u8 ch, s16 sampleRate, u32 vol, const u32 *const data, const u32 *const data2, u32 size, u16 flags)
|
||||
{
|
||||
REG_CSND_CH_SR(ch) = sampleRate;
|
||||
REG_CSND_CH_VOL(ch) = vol;
|
||||
REG_CSND_CH_CAPVOL(ch) = vol;
|
||||
REG_CSND_CH_ST_ADDR(ch) = (u32)data;
|
||||
REG_CSND_CH_SIZE(ch) = size;
|
||||
REG_CSND_CH_LP_ADDR(ch) = (u32)data2;
|
||||
REG_CSND_CH_ST_ADPCM(ch) = 0; // Hardcoded for now. TODO
|
||||
REG_CSND_CH_LP_ADPCM(ch) = 0; // Hardcoded for now. TODO
|
||||
REG_CSND_CH_CNT(ch) = CSND_CH_START | flags; // Start in paused state.
|
||||
}
|
||||
|
||||
|
||||
void CSND_startCap(u8 ch, s16 sampleRate, u32 *const data, u32 size, u16 flags)
|
||||
{
|
||||
REG_CSND_CAP_SR(ch) = sampleRate;
|
||||
REG_CSND_CAP_SIZE(ch) = size;
|
||||
REG_CSND_CAP_ADDR(ch) = (u32)data;
|
||||
REG_CSND_CAP_CNT(ch) = CSND_CAP_START | flags;
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
* 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"
|
||||
#include "arm.h"
|
||||
#include "mem_map.h"
|
||||
|
||||
.cpu mpcore
|
||||
.fpu vfpv2
|
||||
|
||||
.macro EXCEPTION_ENTRY name, type
|
||||
BEGIN_ASM_FUNC \name
|
||||
msr cpsr_f, #\type @ Abuse conditional flags in cpsr for temporary exception type storage
|
||||
b exceptionHandler
|
||||
END_ASM_FUNC
|
||||
.endm
|
||||
|
||||
|
||||
|
||||
EXCEPTION_ENTRY undefInstrHandler, 0<<29
|
||||
EXCEPTION_ENTRY prefetchAbortHandler, 1<<29
|
||||
EXCEPTION_ENTRY dataAbortHandler, 2<<29
|
||||
BEGIN_ASM_FUNC exceptionHandler
|
||||
sub sp, #68
|
||||
stmia sp, {r0-r14}^ @ Save all user/system mode regs except pc
|
||||
mrs r2, spsr @ Get saved cpsr
|
||||
mrs r3, cpsr
|
||||
lsr r0, r3, #29 @ Get back the exception type from cpsr
|
||||
and r1, r2, #PSR_MODE_MASK
|
||||
cmp r1, #PSR_USER_MODE
|
||||
beq exceptionHandler_skip_other_mode
|
||||
add r4, sp, #32
|
||||
msr cpsr_c, r2
|
||||
stmia r4!, {r8-r14} @ Some regs are written twice but we don't care
|
||||
msr cpsr_c, r3
|
||||
exceptionHandler_skip_other_mode:
|
||||
str lr, [sp, #60] @ Save lr (pc) on exception stack
|
||||
str r2, [sp, #64] @ Save spsr (cpsr) on exception stack
|
||||
mov r4, r0
|
||||
mov r5, sp
|
||||
bl deinitCpu
|
||||
mov r0, r4
|
||||
mov sp, r5
|
||||
mov r1, r5
|
||||
b guruMeditation @ r0 = exception type, r1 = reg dump ptr {r0-r14, pc (unmodified), cpsr}
|
||||
END_ASM_FUNC
|
||||
|
||||
|
||||
BEGIN_ASM_FUNC irqHandler
|
||||
sub lr, lr, #4
|
||||
srsfd sp!, #PSR_SYS_MODE @ Store lr and spsr on system mode stack
|
||||
cps #PSR_SYS_MODE
|
||||
stmfd sp!, {r0-r3, r12, lr}
|
||||
ldr r12, =MPCORE_PRIV_REG_BASE
|
||||
ldr r2, =irqIsrTable
|
||||
ldr r0, [r12, #0x10C] @ REG_GIC_CPU_INTACK
|
||||
and r1, r0, #0x7F
|
||||
cmp r1, #32
|
||||
mrclo p15, 0, r3, c0, c0, 5 @ Get CPU ID
|
||||
andlo r3, r3, #3
|
||||
addlo r1, r1, r3, lsl #5
|
||||
addhs r1, r1, #96
|
||||
ldr r3, [r2, r1, lsl #2]
|
||||
cmp r3, #0
|
||||
beq irqHandler_skip_processing
|
||||
cpsie i
|
||||
str r0, [sp, #-4]! @ A single ldr/str can't be interrupted
|
||||
blx r3
|
||||
ldr r0, [sp], #4
|
||||
ldr r12, =MPCORE_PRIV_REG_BASE
|
||||
cpsid i
|
||||
irqHandler_skip_processing:
|
||||
str r0, [r12, #0x110] @ REG_GIC_CPU_EOI
|
||||
ldmfd sp!, {r0-r3, r12, lr}
|
||||
rfefd sp! @ Restore lr (pc) and spsr (cpsr)
|
||||
END_ASM_FUNC
|
|
@ -1,499 +0,0 @@
|
|||
/*
|
||||
* 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 <string.h>
|
||||
#include <stdatomic.h>
|
||||
#include "types.h"
|
||||
#include "fb_assert.h"
|
||||
#include "hardware/gfx.h"
|
||||
#include "arm11/hardware/cfg11.h"
|
||||
#include "arm11/hardware/pdn.h"
|
||||
#include "arm11/hardware/lcd.h"
|
||||
#include "arm11/hardware/gx.h"
|
||||
#include "arm11/hardware/gpu_regs.h"
|
||||
#include "mem_map.h"
|
||||
#include "mmio.h"
|
||||
#include "arm11/hardware/i2c.h"
|
||||
#include "arm11/hardware/mcu.h"
|
||||
#include "arm11/debug.h"
|
||||
#include "arm11/hardware/interrupt.h"
|
||||
#include "arm11/hardware/timer.h"
|
||||
#include "arm.h"
|
||||
#include "util.h"
|
||||
#include "arm11/allocator/vram.h"
|
||||
|
||||
|
||||
static struct
|
||||
{
|
||||
u8 lcdPower; // 1 = on. Bit 4 top light, bit 2 bottom light, bit 0 LCDs.
|
||||
u8 lcdLights[2]; // LCD backlight brightness. Top, bottom.
|
||||
bool events[6];
|
||||
u32 swap; // Currently active framebuffer.
|
||||
void *framebufs[2][4]; // For each screen A1, A2, B1, B2
|
||||
u8 doubleBuf[2]; // Top, bottom, 1 = enable.
|
||||
u16 strides[2]; // Top, bottom
|
||||
u32 formats[2]; // Top, bottom
|
||||
} g_gfxState = {0};
|
||||
|
||||
|
||||
|
||||
static u8 fmt2PixSize(GfxFbFmt fmt);
|
||||
static void setupFramebufs(GfxFbFmt fmtTop, GfxFbFmt fmtBot);
|
||||
static void deallocFramebufs(void);
|
||||
static void setupDislayController(u8 lcd);
|
||||
static void gfxIrqHandler(u32 intSource);
|
||||
|
||||
void GFX_init(GfxFbFmt fmtTop, GfxFbFmt fmtBot)
|
||||
{
|
||||
setupFramebufs(fmtTop, fmtBot);
|
||||
g_gfxState.doubleBuf[0] = 1;
|
||||
g_gfxState.doubleBuf[1] = 1;
|
||||
|
||||
REG_CFG11_GPUPROT = 0;
|
||||
|
||||
// Reset
|
||||
REG_PDN_GPU_CNT = PDN_GPU_CNT_CLK_E;
|
||||
wait(12);
|
||||
REG_PDN_GPU_CNT = PDN_GPU_CNT_CLK_E | PDN_GPU_CNT_RST_ALL;
|
||||
REG_GX_GPU_CLK = 0x100;
|
||||
REG_GX_PSC_VRAM = 0;
|
||||
REG_GX_PSC_FILL0_CNT = 0;
|
||||
REG_GX_PSC_FILL1_CNT = 0;
|
||||
REG_GX_PPF_CNT = 0;
|
||||
|
||||
// LCD framebuffer setup.
|
||||
setupDislayController(0);
|
||||
setupDislayController(1);
|
||||
REG_LCD_PDC0_SWAP = 0; // Select framebuf 0.
|
||||
REG_LCD_PDC1_SWAP = 0;
|
||||
REG_LCD_PDC0_CNT = PDC_CNT_OUT_E | PDC_CNT_I_MASK_ERR | PDC_CNT_I_MASK_H | PDC_CNT_E; // Start
|
||||
REG_LCD_PDC1_CNT = PDC_CNT_OUT_E | PDC_CNT_I_MASK_ERR | PDC_CNT_I_MASK_H | PDC_CNT_E;
|
||||
|
||||
// LCD reg setup.
|
||||
REG_LCD_ABL0_FILL = 1u<<24; // Force blackscreen
|
||||
REG_LCD_ABL1_FILL = 1u<<24; // Force blackscreen
|
||||
REG_LCD_PARALLAX_CNT = 0;
|
||||
REG_LCD_PARALLAX_PWM = 0xA390A39;
|
||||
REG_LCD_RST = 0;
|
||||
REG_LCD_UNK00C = 0x10001;
|
||||
|
||||
// Register IRQ handlers.
|
||||
IRQ_registerIsr(IRQ_PSC0, 14, 0, gfxIrqHandler);
|
||||
IRQ_registerIsr(IRQ_PSC1, 14, 0, gfxIrqHandler);
|
||||
IRQ_registerIsr(IRQ_PDC0, 14, 0, gfxIrqHandler);
|
||||
//IRQ_registerIsr(IRQ_PDC1, 14, 0, gfxIrqHandler);
|
||||
IRQ_registerIsr(IRQ_PPF, 14, 0, gfxIrqHandler);
|
||||
IRQ_registerIsr(IRQ_P3D, 14, 0, gfxIrqHandler);
|
||||
|
||||
// Clear entire VRAM.
|
||||
GX_memoryFill((u32*)VRAM_BANK0, 1u<<9, VRAM_SIZE / 2, 0,
|
||||
(u32*)VRAM_BANK1, 1u<<9, VRAM_SIZE / 2, 0);
|
||||
|
||||
// Backlight and other stuff.
|
||||
REG_LCD_ABL0_LIGHT = 0;
|
||||
REG_LCD_ABL0_CNT = 0;
|
||||
REG_LCD_ABL0_LIGHT_PWM = 0;
|
||||
REG_LCD_ABL1_LIGHT = 0;
|
||||
REG_LCD_ABL1_CNT = 0;
|
||||
REG_LCD_ABL1_LIGHT_PWM = 0;
|
||||
|
||||
REG_LCD_RST = 1;
|
||||
REG_LCD_UNK00C = 0;
|
||||
TIMER_sleepMs(10);
|
||||
LCDI2C_init();
|
||||
MCU_controlLCDPower(2u); // Power on LCDs.
|
||||
if(MCU_waitEvents(0x3Fu<<24) != 2u<<24) panic();
|
||||
|
||||
// The transfer engine is (sometimes) borked on screen init.
|
||||
// Doing a dummy texture copy fixes it.
|
||||
// TODO: Proper fix.
|
||||
//GX_textureCopy((u32*)RENDERBUF_TOP, 0, (u32*)RENDERBUF_BOT, 0, 16);
|
||||
|
||||
LCDI2C_waitBacklightsOn();
|
||||
REG_LCD_ABL0_LIGHT_PWM = 0x1023E;
|
||||
REG_LCD_ABL1_LIGHT_PWM = 0x1023E;
|
||||
MCU_controlLCDPower(0x28u); // Power on backlights.
|
||||
if(MCU_waitEvents(0x3Fu<<24) != 0x28u<<24) panic();
|
||||
g_gfxState.lcdPower = 0x15; // All on.
|
||||
|
||||
// Make sure the fills finished.
|
||||
GFX_waitForPSC0();
|
||||
GFX_waitForPSC1();
|
||||
REG_LCD_ABL0_FILL = 0;
|
||||
REG_LCD_ABL1_FILL = 0;
|
||||
|
||||
// GPU stuff.
|
||||
REG_GX_GPU_CLK = 0x70100;
|
||||
*((vu32*)0x10400050) = 0x22221200;
|
||||
*((vu32*)0x10400054) = 0xFF2;
|
||||
|
||||
REG_GX_P3D(GPUREG_IRQ_ACK) = 0;
|
||||
REG_GX_P3D(GPUREG_IRQ_CMP) = 0x12345678;
|
||||
REG_GX_P3D(GPUREG_IRQ_MASK) = 0xFFFFFFF0;
|
||||
REG_GX_P3D(GPUREG_IRQ_AUTOSTOP) = 1;
|
||||
|
||||
// This reg needs to be set to 1 (configuration)
|
||||
// before running the first cmd list.
|
||||
REG_GX_P3D(GPUREG_START_DRAW_FUNC0) = 1;
|
||||
}
|
||||
|
||||
void GFX_deinit(void)
|
||||
{
|
||||
const u8 power = g_gfxState.lcdPower;
|
||||
if(power & ~1u) // Poweroff backlights if on.
|
||||
{
|
||||
MCU_controlLCDPower(power & ~1u);
|
||||
if(MCU_waitEvents(0x3Fu<<24) != (u32)(power & ~1u)<<24) panic();
|
||||
}
|
||||
if(power & 1u) // Poweroff LCDs if on.
|
||||
{
|
||||
MCU_controlLCDPower(1u);
|
||||
if(MCU_waitEvents(0x3Fu<<24) != 1u<<24) panic();
|
||||
}
|
||||
GFX_setBrightness(0, 0);
|
||||
REG_LCD_ABL0_LIGHT_PWM = 0;
|
||||
REG_LCD_ABL1_LIGHT_PWM = 0;
|
||||
REG_LCD_UNK00C = 0x10001;
|
||||
REG_LCD_RST = 0;
|
||||
REG_GX_PSC_VRAM = 0xF00;
|
||||
REG_GX_GPU_CLK = 0;
|
||||
REG_PDN_GPU_CNT = PDN_GPU_CNT_CLK_E | PDN_GPU_CNT_RST_REGS;
|
||||
|
||||
deallocFramebufs();
|
||||
|
||||
IRQ_unregisterIsr(IRQ_PSC0);
|
||||
IRQ_unregisterIsr(IRQ_PSC1);
|
||||
IRQ_unregisterIsr(IRQ_PDC0);
|
||||
//IRQ_unregisterIsr(IRQ_PDC1);
|
||||
IRQ_unregisterIsr(IRQ_PPF);
|
||||
IRQ_unregisterIsr(IRQ_P3D);
|
||||
}
|
||||
|
||||
void GFX_setFramebufFmt(GfxFbFmt fmtTop, GfxFbFmt fmtBot)
|
||||
{
|
||||
REG_LCD_ABL0_FILL = 1u<<24; // Force blackscreen
|
||||
REG_LCD_ABL1_FILL = 1u<<24; // Force blackscreen
|
||||
|
||||
if(fmtTop < (g_gfxState.formats[0] & 7u) || fmtBot < (g_gfxState.formats[1] & 7u))
|
||||
{
|
||||
deallocFramebufs();
|
||||
setupFramebufs(fmtTop, fmtBot);
|
||||
}
|
||||
|
||||
// Update PDC regs.
|
||||
REG_LCD_PDC0_FB_A1 = (u32)g_gfxState.framebufs[0][0];
|
||||
REG_LCD_PDC0_FB_A2 = (u32)g_gfxState.framebufs[0][1];
|
||||
REG_LCD_PDC0_FB_B1 = (u32)g_gfxState.framebufs[0][2];
|
||||
REG_LCD_PDC0_FB_B2 = (u32)g_gfxState.framebufs[0][3];
|
||||
REG_LCD_PDC0_STRIDE = g_gfxState.strides[0];
|
||||
REG_LCD_PDC0_FMT = g_gfxState.formats[0];
|
||||
|
||||
REG_LCD_PDC1_FB_A1 = (u32)g_gfxState.framebufs[1][0];
|
||||
REG_LCD_PDC1_FB_A2 = (u32)g_gfxState.framebufs[1][1];
|
||||
REG_LCD_PDC1_FB_B1 = (u32)g_gfxState.framebufs[1][2];
|
||||
REG_LCD_PDC1_FB_B2 = (u32)g_gfxState.framebufs[1][3];
|
||||
REG_LCD_PDC1_STRIDE = g_gfxState.strides[1];
|
||||
REG_LCD_PDC1_FMT = g_gfxState.formats[1];
|
||||
|
||||
REG_LCD_ABL0_FILL = 0;
|
||||
REG_LCD_ABL1_FILL = 0;
|
||||
}
|
||||
|
||||
static u8 fmt2PixSize(GfxFbFmt fmt)
|
||||
{
|
||||
u8 size;
|
||||
|
||||
switch(fmt)
|
||||
{
|
||||
case GFX_RGBA8:
|
||||
size = 4;
|
||||
break;
|
||||
case GFX_BGR8:
|
||||
size = 3;
|
||||
break;
|
||||
default: // 2 = RGB565, 3 = RGB5A1, 4 = RGBA4
|
||||
size = 2;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static void setupFramebufs(GfxFbFmt fmtTop, GfxFbFmt fmtBot)
|
||||
{
|
||||
const u8 topPixSize = fmt2PixSize(fmtTop);
|
||||
const u8 botPixSize = fmt2PixSize(fmtBot);
|
||||
g_gfxState.strides[0] = 240u * topPixSize; // No gap.
|
||||
g_gfxState.strides[1] = 240u * botPixSize; // No gap.
|
||||
|
||||
const u32 topSize = 400u * 240 * topPixSize;
|
||||
const u32 botSize = 320u * 240 * botPixSize;
|
||||
g_gfxState.framebufs[0][0] = vramAlloc(topSize); // Top A1 (3D left eye)
|
||||
void *botPtr = vramAlloc(botSize);
|
||||
g_gfxState.framebufs[1][0] = botPtr; // Bottom A1
|
||||
g_gfxState.framebufs[1][2] = botPtr; // Bottom B1 (unused)
|
||||
g_gfxState.framebufs[0][2] = vramAlloc(topSize); // Top B1 (3D right eye)
|
||||
|
||||
g_gfxState.framebufs[0][1] = vramAlloc(topSize); // Top A2 (3D left eye)
|
||||
botPtr = vramAlloc(botSize);
|
||||
g_gfxState.framebufs[1][1] = botPtr; // Bottom A2
|
||||
g_gfxState.framebufs[1][3] = botPtr; // Bottom B2 (unused)
|
||||
g_gfxState.framebufs[0][3] = vramAlloc(topSize); // Top B2 (3D right eye)
|
||||
|
||||
g_gfxState.formats[0] = 0u<<16 | 3u<<8 | 1u<<6 | 0u<<4 | fmtTop;
|
||||
g_gfxState.formats[1] = 0u<<16 | 3u<<8 | 0u<<6 | 0u<<4 | fmtBot;
|
||||
}
|
||||
|
||||
static void deallocFramebufs(void)
|
||||
{
|
||||
vramFree(g_gfxState.framebufs[0][3]);
|
||||
vramFree(g_gfxState.framebufs[1][1]);
|
||||
vramFree(g_gfxState.framebufs[0][1]);
|
||||
vramFree(g_gfxState.framebufs[0][2]);
|
||||
vramFree(g_gfxState.framebufs[1][0]);
|
||||
vramFree(g_gfxState.framebufs[0][0]);
|
||||
}
|
||||
|
||||
static void setupDislayController(u8 lcd)
|
||||
{
|
||||
if(lcd > 1) return;
|
||||
|
||||
static const u32 displayCfgs[2][24] =
|
||||
{
|
||||
{
|
||||
// PDC0 regs 0-0x4C.
|
||||
450, 209, 449, 449, 0, 207, 209, 453<<16 | 449,
|
||||
1<<16 | 0, 413, 2, 402, 402, 402, 1, 2,
|
||||
406<<16 | 402, 0, 0<<4 | 0, 0<<16 | 0xFF<<8 | 0,
|
||||
// PDC0 regs 0x5C-0x64.
|
||||
400<<16 | 240, // Width and height.
|
||||
449<<16 | 209,
|
||||
402<<16 | 2,
|
||||
// PDC0 reg 0x9C.
|
||||
0<<16 | 0
|
||||
},
|
||||
{
|
||||
// PDC1 regs 0-0x4C.
|
||||
450, 209, 449, 449, 205, 207, 209, 453<<16 | 449,
|
||||
1<<16 | 0, 413, 82, 402, 402, 79, 80, 82,
|
||||
408<<16 | 404, 0, 1<<4 | 1, 0<<16 | 0<<8 | 0xFF,
|
||||
// PDC1 regs 0x5C-0x64.
|
||||
320<<16 | 240, // Width and height.
|
||||
449<<16 | 209,
|
||||
402<<16 | 82,
|
||||
// PDC1 reg 0x9C.
|
||||
0<<16 | 0
|
||||
}
|
||||
};
|
||||
|
||||
const u32 *const cfg = displayCfgs[lcd];
|
||||
vu32 *const regs = (vu32*)(GX_REGS_BASE + 0x400 + (0x100u * lcd));
|
||||
|
||||
iomemcpy(regs, cfg, 0x50); // PDC regs 0-0x4C.
|
||||
iomemcpy(regs + 23, &cfg[20], 0xC); // PDC regs 0x5C-0x64.
|
||||
regs[36] = g_gfxState.strides[lcd]; // PDC reg 0x90 stride.
|
||||
regs[39] = cfg[23]; // PDC reg 0x9C.
|
||||
|
||||
|
||||
// PDC regs 0x68, 0x6C, 0x94, 0x98 and 0x70.
|
||||
regs[26] = (u32)g_gfxState.framebufs[lcd][0]; // Framebuffer A first address.
|
||||
regs[27] = (u32)g_gfxState.framebufs[lcd][1]; // Framebuffer A second address.
|
||||
regs[37] = (u32)g_gfxState.framebufs[lcd][2]; // Framebuffer B first address.
|
||||
regs[38] = (u32)g_gfxState.framebufs[lcd][3]; // Framebuffer B second address.
|
||||
regs[28] = g_gfxState.formats[lcd]; // Format
|
||||
|
||||
|
||||
regs[32] = 0; // Gamma table index 0.
|
||||
for(u32 i = 0; i < 256; i++) regs[33] = 0x10101u * i;
|
||||
}
|
||||
|
||||
void GFX_powerOnBacklights(GfxBlight mask)
|
||||
{
|
||||
fb_assert((mask & ~GFX_BLIGHT_BOTH) == 0u);
|
||||
g_gfxState.lcdPower |= mask;
|
||||
|
||||
mask <<= 1;
|
||||
MCU_controlLCDPower(mask); // Power on backlights.
|
||||
if(MCU_waitEvents(0x3Fu<<24) != (u32)mask<<24) panic();
|
||||
}
|
||||
|
||||
void GFX_powerOffBacklights(GfxBlight mask)
|
||||
{
|
||||
fb_assert((mask & ~GFX_BLIGHT_BOTH) == 0u);
|
||||
g_gfxState.lcdPower &= ~mask;
|
||||
|
||||
MCU_controlLCDPower(mask); // Power off backlights.
|
||||
if(MCU_waitEvents(0x3Fu<<24) != (u32)mask<<24) panic();
|
||||
}
|
||||
|
||||
void GFX_setBrightness(u8 top, u8 bot)
|
||||
{
|
||||
if(top > 64 || bot > 64) return;
|
||||
|
||||
g_gfxState.lcdLights[0] = top;
|
||||
g_gfxState.lcdLights[1] = bot;
|
||||
REG_LCD_ABL0_LIGHT = top;
|
||||
REG_LCD_ABL1_LIGHT = bot;
|
||||
}
|
||||
|
||||
void GFX_setForceBlack(bool top, bool bot)
|
||||
{
|
||||
REG_LCD_ABL0_FILL = (u32)top<<24; // Force blackscreen
|
||||
REG_LCD_ABL1_FILL = (u32)bot<<24; // Force blackscreen
|
||||
}
|
||||
|
||||
void GFX_setDoubleBuffering(u8 screen, bool dBuf)
|
||||
{
|
||||
g_gfxState.doubleBuf[screen] = dBuf;
|
||||
|
||||
if(!dBuf)
|
||||
{
|
||||
if(screen == SCREEN_TOP) REG_LCD_PDC0_SWAP = 0;
|
||||
else REG_LCD_PDC1_SWAP = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void* GFX_getFramebuffer(u8 screen)
|
||||
{
|
||||
const u32 idx = (g_gfxState.swap ^ 1u) & g_gfxState.doubleBuf[screen];
|
||||
return g_gfxState.framebufs[screen][idx];
|
||||
}
|
||||
|
||||
void GFX_swapFramebufs(void)
|
||||
{
|
||||
u32 swap = g_gfxState.swap;
|
||||
swap ^= 1u;
|
||||
g_gfxState.swap = swap;
|
||||
|
||||
swap |= PDC_SWAP_I_ALL; // Acknowledge IRQs.
|
||||
if(g_gfxState.doubleBuf[0]) REG_LCD_PDC0_SWAP = swap;
|
||||
if(g_gfxState.doubleBuf[1]) REG_LCD_PDC1_SWAP = swap;
|
||||
}
|
||||
|
||||
void GFX_waitForEvent(GfxEvent event, bool discard)
|
||||
{
|
||||
bool *const events = g_gfxState.events;
|
||||
|
||||
if(discard) atomic_store_explicit(&events[event], false, memory_order_relaxed);
|
||||
while(!atomic_load_explicit(&events[event], memory_order_relaxed)) __wfe();
|
||||
atomic_store_explicit(&events[event], false, memory_order_relaxed);
|
||||
}
|
||||
|
||||
static void gfxIrqHandler(u32 intSource)
|
||||
{
|
||||
bool *const events = g_gfxState.events;
|
||||
|
||||
atomic_store_explicit(&events[intSource - IRQ_PSC0], true, memory_order_relaxed);
|
||||
}
|
||||
|
||||
void GX_memoryFill(u32 *buf0a, u32 buf0v, u32 buf0Sz, u32 val0, u32 *buf1a, u32 buf1v, u32 buf1Sz, u32 val1)
|
||||
{
|
||||
if(buf0a)
|
||||
{
|
||||
REG_GX_PSC_FILL0_S_ADDR = (u32)buf0a>>3;
|
||||
REG_GX_PSC_FILL0_E_ADDR = ((u32)buf0a + buf0Sz)>>3;
|
||||
REG_GX_PSC_FILL0_VAL = val0;
|
||||
REG_GX_PSC_FILL0_CNT = buf0v | 1u; // Pattern + start
|
||||
}
|
||||
|
||||
if(buf1a)
|
||||
{
|
||||
REG_GX_PSC_FILL1_S_ADDR = (u32)buf1a>>3;
|
||||
REG_GX_PSC_FILL1_E_ADDR = ((u32)buf1a + buf1Sz)>>3;
|
||||
REG_GX_PSC_FILL1_VAL = val1;
|
||||
REG_GX_PSC_FILL1_CNT = buf1v | 1u; // Pattern + start
|
||||
}
|
||||
}
|
||||
|
||||
// Example: GX_displayTransfer(in, 160u<<16 | 240u, out, 160u<<16 | 240u, 2u<<12 | 2u<<8);
|
||||
// Copy and unswizzle GBA sized frame in RGB565.
|
||||
void GX_displayTransfer(const u32 *const in, u32 indim, u32 *out, u32 outdim, u32 flags)
|
||||
{
|
||||
if(!in || !out) return;
|
||||
|
||||
REG_GX_PPF_IN_ADDR = (u32)in>>3;
|
||||
REG_GX_PPF_OUT_ADDR = (u32)out>>3;
|
||||
REG_GX_PPF_DT_INDIM = indim;
|
||||
REG_GX_PPF_DT_OUTDIM = outdim;
|
||||
REG_GX_PPF_FlAGS = flags;
|
||||
REG_GX_PPF_UNK14 = 0;
|
||||
REG_GX_PPF_CNT = 1;
|
||||
}
|
||||
|
||||
// Example: GX_textureCopy(in, (240 * 2)<<12 | (240 * 2)>>4, out, (240 * 2)<<12 | (240 * 2)>>4, 240 * 400);
|
||||
// Copies every second line of a 240x400 framebuffer.
|
||||
void GX_textureCopy(const u32 *const in, u32 indim, u32 *out, u32 outdim, u32 size)
|
||||
{
|
||||
if(!in || !out) return;
|
||||
|
||||
REG_GX_PPF_IN_ADDR = (u32)in>>3;
|
||||
REG_GX_PPF_OUT_ADDR = (u32)out>>3;
|
||||
REG_GX_PPF_FlAGS = 1u<<3;
|
||||
REG_GX_PPF_LEN = size;
|
||||
REG_GX_PPF_TC_INDIM = indim;
|
||||
REG_GX_PPF_TC_OUTDIM = outdim;
|
||||
REG_GX_PPF_CNT = 1;
|
||||
}
|
||||
|
||||
void GX_processCommandList(u32 size, const u32 *const cmdList)
|
||||
{
|
||||
REG_GX_P3D(GPUREG_IRQ_ACK) = 0; // Acknowledge last P3D.
|
||||
while(REG_GX_PSC_STAT & 1u<<31) wait(0x30);
|
||||
|
||||
REG_GX_P3D(GPUREG_CMDBUF_SIZE0) = size>>3;
|
||||
REG_GX_P3D(GPUREG_CMDBUF_ADDR0) = (u32)cmdList>>3;
|
||||
REG_GX_P3D(GPUREG_CMDBUF_JUMP0) = 1;
|
||||
}
|
||||
|
||||
// TODO: Sleep mode stuff needs some work.
|
||||
/*void GFX_enterLowPowerState(void)
|
||||
{
|
||||
REG_LCD_ABL0_FILL = 1u<<24; // Force blackscreen
|
||||
REG_LCD_ABL1_FILL = 1u<<24; // Force blackscreen
|
||||
GFX_waitForEvent(GFX_EVENT_PDC0, true);
|
||||
|
||||
// Stop PDCs.
|
||||
REG_LCD_PDC0_CNT = 0x700; // Stop
|
||||
REG_LCD_PDC1_CNT = 0x700; // Stop
|
||||
REG_LCD_PDC0_SWAP = 0x70100;
|
||||
REG_LCD_PDC1_SWAP = 0x70100;
|
||||
|
||||
REG_GX_PSC_VRAM = 0xF00;
|
||||
REG_PDN_GPU_CNT = PDN_GPU_CNT_RST_ALL;
|
||||
}
|
||||
|
||||
void GFX_returnFromLowPowerState(void)
|
||||
{
|
||||
REG_PDN_GPU_CNT = PDN_GPU_CNT_CLK_E | PDN_GPU_CNT_RST_ALL;
|
||||
REG_GX_PSC_VRAM = 0;
|
||||
//REG_GX_GPU_CLK = 0x70100;
|
||||
REG_GX_PSC_FILL0_CNT = 0;
|
||||
REG_GX_PSC_FILL1_CNT = 0;
|
||||
// *((vu32*)0x10400050) = 0x22221200;
|
||||
// *((vu32*)0x10400054) = 0xFF2;
|
||||
|
||||
setupDislayController(0);
|
||||
setupDislayController(1);
|
||||
const u32 swap = 0x70100 | g_gfxState.swap;
|
||||
REG_LCD_PDC0_SWAP = swap;
|
||||
REG_LCD_PDC1_SWAP = swap;
|
||||
REG_LCD_PDC0_CNT = 0x10501; // Start
|
||||
REG_LCD_PDC1_CNT = 0x10501; // Start
|
||||
|
||||
REG_LCD_ABL0_FILL = 0;
|
||||
REG_LCD_ABL1_FILL = 0;
|
||||
}*/
|
|
@ -1,112 +0,0 @@
|
|||
/*
|
||||
* 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 "arm11/hardware/gpio.h"
|
||||
|
||||
|
||||
#define GPIO_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x47000)
|
||||
// 3 GPIOs (bits 0-2)
|
||||
#define REG_GPIO1_DAT *((const vu8*)(GPIO_REGS_BASE + 0x00)) // Read-only.
|
||||
|
||||
// 2 GPIOs (bits 0-1)
|
||||
#define REG_GPIO2 *(( vu32*)(GPIO_REGS_BASE + 0x10))
|
||||
#define REG_GPIO2_DAT *(( vu8*)(GPIO_REGS_BASE + 0x10))
|
||||
#define REG_GPIO2_DIR *(( vu8*)(GPIO_REGS_BASE + 0x11)) // 0 = input, 1 = output.
|
||||
#define REG_GPIO2_EDGE *(( vu8*)(GPIO_REGS_BASE + 0x12)) // IRQ edge 0 = falling, 1 = rising.
|
||||
#define REG_GPIO2_IRQ *(( vu8*)(GPIO_REGS_BASE + 0x13)) // 1 = IRQ enable.
|
||||
// 1 GPIO (bit 0)
|
||||
#define REG_GPIO2_DAT2 *(( vu16*)(GPIO_REGS_BASE + 0x14)) // Only bit 0 writable.
|
||||
|
||||
// 12 GPIOs (bits 0-11)
|
||||
#define REG_GPIO3_H1 *(( vu32*)(GPIO_REGS_BASE + 0x20)) // First half.
|
||||
#define REG_GPIO3_DAT *(( vu16*)(GPIO_REGS_BASE + 0x20))
|
||||
#define REG_GPIO3_DIR *(( vu16*)(GPIO_REGS_BASE + 0x22))
|
||||
#define REG_GPIO3_H2 *(( vu32*)(GPIO_REGS_BASE + 0x24)) // Second half.
|
||||
#define REG_GPIO3_EDGE *(( vu16*)(GPIO_REGS_BASE + 0x24))
|
||||
#define REG_GPIO3_IRQ *(( vu16*)(GPIO_REGS_BASE + 0x26))
|
||||
// 1 GPIO (bit 0)
|
||||
#define REG_GPIO3_DAT2 *(( vu16*)(GPIO_REGS_BASE + 0x28)) // WiFi.
|
||||
|
||||
|
||||
static vu16 *const datRegs[5] = {(vu16*)®_GPIO1_DAT, (vu16*)®_GPIO2_DAT, ®_GPIO2_DAT2, ®_GPIO3_DAT, ®_GPIO3_DAT2};
|
||||
|
||||
|
||||
|
||||
void GPIO_config(Gpio gpio, u8 cfg)
|
||||
{
|
||||
const u8 regIdx = gpio & 7u;
|
||||
const u8 pinNum = gpio>>3;
|
||||
|
||||
// GPIO1 and GPIO3_DAT2 are not configurable.
|
||||
if(regIdx == 1)
|
||||
{
|
||||
u32 reg = REG_GPIO2 & ~((1u<<24 | 1u<<16 | 1u<<8)<<pinNum);
|
||||
|
||||
if(cfg & GPIO_OUTPUT) reg |= (1u<<8)<<pinNum; // Direction.
|
||||
if(cfg & GPIO_EDGE_RISING) reg |= (1u<<16)<<pinNum; // IRQ edge.
|
||||
if(cfg & GPIO_IRQ_ENABLE) reg |= (1u<<24)<<pinNum; // IRQ enable.
|
||||
|
||||
REG_GPIO2 = reg;
|
||||
}
|
||||
else if(regIdx == 3)
|
||||
{
|
||||
u32 reg = REG_GPIO3_H1 & ~((1u<<16)<<pinNum);
|
||||
u32 reg2 = REG_GPIO3_H2 & ~((1u<<16 | 1u)<<pinNum);
|
||||
|
||||
if(cfg & GPIO_OUTPUT) reg |= (1u<<16)<<pinNum; // Direction.
|
||||
if(cfg & GPIO_EDGE_RISING) reg2 |= 1u<<pinNum; // IRQ edge.
|
||||
if(cfg & GPIO_IRQ_ENABLE) reg2 |= (1u<<16)<<pinNum; // IRQ enable.
|
||||
|
||||
REG_GPIO3_H1 = reg;
|
||||
REG_GPIO3_H2 = reg2;
|
||||
}
|
||||
}
|
||||
|
||||
bool GPIO_read(Gpio gpio)
|
||||
{
|
||||
const u8 regIdx = gpio & 7u;
|
||||
const u8 pinNum = gpio>>3;
|
||||
|
||||
if(regIdx > 4) return 0;
|
||||
|
||||
return *datRegs[regIdx]>>pinNum & 1u;
|
||||
}
|
||||
|
||||
void GPIO_write(Gpio gpio, bool val)
|
||||
{
|
||||
const u8 regIdx = gpio & 7u;
|
||||
const u8 pinNum = gpio>>3;
|
||||
|
||||
if(regIdx == 0 || regIdx > 4) return;
|
||||
|
||||
u16 tmp = *datRegs[regIdx];
|
||||
tmp &= ~(1u<<pinNum) | (u16)val<<pinNum;
|
||||
*datRegs[regIdx] = tmp;
|
||||
}
|
||||
|
||||
/*#include "arm11/fmt.h"
|
||||
void GPIO_dbgPrint(void)
|
||||
{
|
||||
ee_printf("REG_GPIO1_DAT %04" PRIx8 "\n", REG_GPIO1_DAT);
|
||||
ee_printf("REG_GPIO2_DAT %02" PRIx8 "\nREG_GPIO2_DIR %02" PRIx8 "\nREG_GPIO2_EDGE %02" PRIx8 "\nREG_GPIO2_IRQ %02" PRIx8 "\n", REG_GPIO2_DAT, REG_GPIO2_DIR, REG_GPIO2_EDGE, REG_GPIO2_IRQ);
|
||||
ee_printf("REG_GPIO2_DAT2 %04" PRIx16 "\n", REG_GPIO2_DAT2);
|
||||
ee_printf("REG_GPIO3_DAT %04" PRIx16 "\nREG_GPIO3_DIR %04" PRIx16 "\nREG_GPIO3_EDGE %04" PRIx16 "\nREG_GPIO3_IRQ %04" PRIx16 "\n", REG_GPIO3_DAT, REG_GPIO3_DIR, REG_GPIO3_EDGE, REG_GPIO3_IRQ);
|
||||
ee_printf("REG_GPIO3_DAT2 %04" PRIx16 "\n", REG_GPIO3_DAT2);
|
||||
}*/
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
* 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"
|
||||
#include "mem_map.h"
|
||||
#include "arm11/hardware/hash.h"
|
||||
#include "mmio.h"
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////
|
||||
// HASH //
|
||||
//////////////////////////////////
|
||||
|
||||
#define HASH_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x1000)
|
||||
#define REG_HASH_CNT *((vu32*)(HASH_REGS_BASE + 0x00))
|
||||
#define REG_HASH_BLKCNT *((vu32*)(HASH_REGS_BASE + 0x04))
|
||||
#define REGs_HASH_HASH ((vu32*)(HASH_REGS_BASE + 0x40))
|
||||
#define REGs_HASH_INFIFO ((vu32*)(IO_MEM_ARM11_ONLY + 0x101000)) // INFIFO is in the DMA region
|
||||
|
||||
|
||||
void HASH_start(u8 params)
|
||||
{
|
||||
REG_HASH_CNT = params | HASH_IN_DMA_ENABLE | HASH_ENABLE;
|
||||
}
|
||||
|
||||
void HASH_update(const u32 *data, u32 size)
|
||||
{
|
||||
while(size >= 64)
|
||||
{
|
||||
*((volatile _u512*)REGs_HASH_INFIFO) = *((const _u512*)data);
|
||||
data += 64 / 4;
|
||||
size -= 64;
|
||||
while(REG_HASH_CNT & HASH_ENABLE);
|
||||
}
|
||||
|
||||
if(size) iomemcpy(REGs_HASH_INFIFO, data, size);
|
||||
}
|
||||
|
||||
void HASH_finish(u32 *const hash, u8 endianess)
|
||||
{
|
||||
REG_HASH_CNT = (REG_HASH_CNT & HASH_MODE_MASK) | endianess | HASH_FINAL_ROUND;
|
||||
while(REG_HASH_CNT & HASH_ENABLE);
|
||||
|
||||
HASH_getState(hash);
|
||||
}
|
||||
|
||||
void HASH_getState(u32 *const out)
|
||||
{
|
||||
u32 size;
|
||||
switch(REG_HASH_CNT & HASH_MODE_MASK)
|
||||
{
|
||||
case HASH_MODE_256:
|
||||
size = 32;
|
||||
break;
|
||||
case HASH_MODE_224:
|
||||
size = 28;
|
||||
break;
|
||||
case HASH_MODE_1:
|
||||
default: // 2 and 3 are both SHA1
|
||||
size = 20;
|
||||
}
|
||||
|
||||
iomemcpy(out, REGs_HASH_HASH, size);
|
||||
}
|
||||
|
||||
void hash(const u32 *data, u32 size, u32 *const hash, u8 params, u8 hashEndianess)
|
||||
{
|
||||
HASH_start(params);
|
||||
HASH_update(data, size);
|
||||
HASH_finish(hash, hashEndianess);
|
||||
}
|
|
@ -1,149 +0,0 @@
|
|||
/*
|
||||
* 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"
|
||||
#include "arm11/hardware/hid.h"
|
||||
#include "arm11/hardware/mcu.h"
|
||||
#include "arm11/hardware/interrupt.h"
|
||||
#include "arm11/hardware/gpio.h"
|
||||
#include "arm11/hardware/codec.h"
|
||||
|
||||
|
||||
#define CPAD_THRESHOLD (400)
|
||||
|
||||
|
||||
static u32 g_kHeld = 0, g_kDown = 0, g_kUp = 0;
|
||||
static u32 g_extraKeys = 0;
|
||||
TouchPos tPos = {0};
|
||||
CpadPos cPos = {0};
|
||||
|
||||
|
||||
|
||||
void hidInit(void)
|
||||
{
|
||||
static bool inited = false;
|
||||
if(inited) return;
|
||||
inited = true;
|
||||
|
||||
MCU_init();
|
||||
u8 state = MCU_getExternalHwState();
|
||||
u32 tmp = ~state<<3 & KEY_SHELL; // Current shell state. Bit is inverted.
|
||||
tmp |= state<<1 & KEY_BAT_CHARGING; // Current battery charging state
|
||||
state = MCU_getHidHeld();
|
||||
tmp |= ~state<<1 & KEY_HOME; // Current HOME button state
|
||||
g_extraKeys = tmp;
|
||||
|
||||
CODEC_init();
|
||||
}
|
||||
|
||||
static void updateMcuHidState(void)
|
||||
{
|
||||
const u32 state = MCU_getEvents(0x40C07F);
|
||||
if(state == 0) return;
|
||||
|
||||
u32 tmp = g_extraKeys;
|
||||
tmp |= state & (KEY_POWER | KEY_POWER_HELD | KEY_HOME); // Power button pressed/held, HOME button pressed
|
||||
if(state & 1u<<3) tmp &= ~KEY_HOME; // HOME released
|
||||
tmp |= state>>1 & (KEY_WIFI | KEY_SHELL); // WiFi switch, shell closed
|
||||
if(state & 1u<<6) tmp &= ~KEY_SHELL; // Shell opened
|
||||
tmp |= state>>10 & KEY_BAT_CHARGING; // Battery started charging
|
||||
if(state & 1u<<14) tmp &= ~KEY_BAT_CHARGING; // Battery stopped charging
|
||||
tmp |= state>>16 & KEY_VOL_SLIDER; // Volume slider update
|
||||
g_extraKeys = tmp;
|
||||
}
|
||||
|
||||
static u32 rawCodec2Hid(void)
|
||||
{
|
||||
static u32 fakeKeysCache = 0;
|
||||
alignas(4) CdcAdcData adc;
|
||||
if(!CODEC_getRawAdcData(&adc)) return fakeKeysCache;
|
||||
|
||||
// Touchscreen
|
||||
// TODO: Calibration
|
||||
const u16 tx = __builtin_bswap16(adc.touchX[0]);
|
||||
u32 fakeKeys = (~tx & 1u<<12)<<8; // KEY_TOUCH
|
||||
tPos.x = tx * 320u / 4096u;
|
||||
tPos.y = __builtin_bswap16(adc.touchY[0]) * 240u / 4096u;
|
||||
|
||||
// Circle-Pad
|
||||
// TODO: Calibration
|
||||
cPos.y = (__builtin_bswap16(adc.cpadY[0]) & 0xFFFu) - 2048u;
|
||||
cPos.x = -((__builtin_bswap16(adc.cpadX[0]) & 0xFFFu) - 2048u); // X axis is inverted.
|
||||
|
||||
if((cPos.x >= 0 ? cPos.x : -cPos.x) > CPAD_THRESHOLD)
|
||||
{
|
||||
if(cPos.x >= 0) fakeKeys |= KEY_CPAD_RIGHT;
|
||||
else fakeKeys |= KEY_CPAD_LEFT;
|
||||
}
|
||||
if((cPos.y >= 0 ? cPos.y : -cPos.y) > CPAD_THRESHOLD)
|
||||
{
|
||||
if(cPos.y >= 0) fakeKeys |= KEY_CPAD_UP;
|
||||
else fakeKeys |= KEY_CPAD_DOWN;
|
||||
}
|
||||
|
||||
fakeKeysCache = fakeKeys;
|
||||
return fakeKeys;
|
||||
}
|
||||
|
||||
void hidScanInput(void)
|
||||
{
|
||||
updateMcuHidState();
|
||||
|
||||
const u32 kOld = g_kHeld;
|
||||
g_kHeld = rawCodec2Hid() | REG_HID_PAD;
|
||||
g_kDown = (~kOld) & g_kHeld;
|
||||
g_kUp = kOld & (~g_kHeld);
|
||||
}
|
||||
|
||||
u32 hidKeysHeld(void)
|
||||
{
|
||||
return g_kHeld;
|
||||
}
|
||||
|
||||
u32 hidKeysDown(void)
|
||||
{
|
||||
return g_kDown;
|
||||
}
|
||||
|
||||
u32 hidKeysUp(void)
|
||||
{
|
||||
return g_kUp;
|
||||
}
|
||||
|
||||
const TouchPos* hidGetTouchPosPtr(void)
|
||||
{
|
||||
return &tPos;
|
||||
}
|
||||
|
||||
const CpadPos* hidGetCpadPosPtr(void)
|
||||
{
|
||||
return &cPos;
|
||||
}
|
||||
|
||||
u32 hidGetExtraKeys(u32 clearMask)
|
||||
{
|
||||
const u32 tmp = g_extraKeys;
|
||||
g_extraKeys &= ~clearMask;
|
||||
|
||||
return tmp;
|
||||
}
|
|
@ -1,267 +0,0 @@
|
|||
/*
|
||||
* 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 "arm11/hardware/i2c.h"
|
||||
#include "arm11/hardware/interrupt.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vu8 I2C_DATA;
|
||||
vu8 I2C_CNT;
|
||||
vu16 I2C_CNTEX;
|
||||
vu16 I2C_SCL;
|
||||
} I2cRegs;
|
||||
|
||||
enum
|
||||
{
|
||||
I2C_BUS1 = 0u,
|
||||
I2C_BUS2 = 1u,
|
||||
I2C_BUS3 = 2u
|
||||
};
|
||||
|
||||
static const struct
|
||||
{
|
||||
u8 busId;
|
||||
u8 devAddr;
|
||||
} i2cDevTable[] =
|
||||
{
|
||||
{I2C_BUS1, 0x4A},
|
||||
{I2C_BUS1, 0x7A},
|
||||
{I2C_BUS1, 0x78},
|
||||
{I2C_BUS2, 0x4A},
|
||||
{I2C_BUS2, 0x78},
|
||||
{I2C_BUS2, 0x2C},
|
||||
{I2C_BUS2, 0x2E},
|
||||
{I2C_BUS2, 0x40},
|
||||
{I2C_BUS2, 0x44},
|
||||
{I2C_BUS3, 0xD6},
|
||||
{I2C_BUS3, 0xD0},
|
||||
{I2C_BUS3, 0xD2},
|
||||
{I2C_BUS3, 0xA4},
|
||||
{I2C_BUS3, 0x9A},
|
||||
{I2C_BUS3, 0xA0},
|
||||
{I2C_BUS2, 0xEE},
|
||||
{I2C_BUS1, 0x40},
|
||||
{I2C_BUS3, 0x54}
|
||||
};
|
||||
|
||||
|
||||
|
||||
static I2cRegs* i2cGetBusRegsBase(u8 busId)
|
||||
{
|
||||
I2cRegs *base;
|
||||
switch(busId)
|
||||
{
|
||||
case I2C_BUS1:
|
||||
base = (I2cRegs*)I2C1_REGS_BASE;
|
||||
break;
|
||||
case I2C_BUS2:
|
||||
base = (I2cRegs*)I2C2_REGS_BASE;
|
||||
break;
|
||||
case I2C_BUS3:
|
||||
base = (I2cRegs*)I2C3_REGS_BASE;
|
||||
break;
|
||||
default:
|
||||
base = NULL;
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
static inline void i2cWaitBusyIrq(const I2cRegs *const regs)
|
||||
{
|
||||
do
|
||||
{
|
||||
__wfi();
|
||||
} while(regs->I2C_CNT & I2C_ENABLE);
|
||||
}
|
||||
|
||||
static bool i2cCheckAck(I2cRegs *const regs)
|
||||
{
|
||||
// If we received a NACK stop the transfer.
|
||||
if((regs->I2C_CNT & I2C_ACK) == 0u)
|
||||
{
|
||||
regs->I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void I2C_init(void)
|
||||
{
|
||||
static bool inited = false;
|
||||
if(inited) return;
|
||||
inited = true;
|
||||
|
||||
I2cRegs *regs = i2cGetBusRegsBase(I2C_BUS1);
|
||||
while(regs->I2C_CNT & I2C_ENABLE);
|
||||
regs->I2C_CNTEX = I2C_CLK_STRETCH;
|
||||
regs->I2C_SCL = I2C_DELAYS(5u, 0u);
|
||||
|
||||
regs = i2cGetBusRegsBase(I2C_BUS2);
|
||||
while(regs->I2C_CNT & I2C_ENABLE);
|
||||
regs->I2C_CNTEX = I2C_CLK_STRETCH;
|
||||
regs->I2C_SCL = I2C_DELAYS(5u, 0u);
|
||||
|
||||
regs = i2cGetBusRegsBase(I2C_BUS3);
|
||||
while(regs->I2C_CNT & I2C_ENABLE);
|
||||
regs->I2C_CNTEX = I2C_CLK_STRETCH;
|
||||
regs->I2C_SCL = I2C_DELAYS(5u, 0u);
|
||||
|
||||
IRQ_registerIsr(IRQ_I2C1, 14, 0, NULL);
|
||||
IRQ_registerIsr(IRQ_I2C2, 14, 0, NULL);
|
||||
IRQ_registerIsr(IRQ_I2C3, 14, 0, NULL);
|
||||
}
|
||||
|
||||
static bool i2cStartTransfer(u8 devAddr, u8 regAddr, bool read, I2cRegs *const regs)
|
||||
{
|
||||
u32 tries = 8;
|
||||
do
|
||||
{
|
||||
// Edge case on previous transfer error.
|
||||
// This is a special case where we can't predict when or if
|
||||
// the IRQ has already fired. If it fires after checking but
|
||||
// before a wfi this would hang.
|
||||
while(regs->I2C_CNT & I2C_ENABLE) __wfe();
|
||||
|
||||
// Select device and start.
|
||||
regs->I2C_DATA = devAddr;
|
||||
regs->I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIR_WRITE | I2C_START;
|
||||
i2cWaitBusyIrq(regs);
|
||||
if(!i2cCheckAck(regs)) continue;
|
||||
|
||||
// Select register.
|
||||
regs->I2C_DATA = regAddr;
|
||||
regs->I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIR_WRITE;
|
||||
i2cWaitBusyIrq(regs);
|
||||
if(!i2cCheckAck(regs)) continue;
|
||||
|
||||
// Select device in read mode for read transfer.
|
||||
if(read)
|
||||
{
|
||||
regs->I2C_DATA = devAddr | 1u; // Set bit 0 for read.
|
||||
regs->I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIR_WRITE | I2C_START;
|
||||
i2cWaitBusyIrq(regs);
|
||||
if(!i2cCheckAck(regs)) continue;
|
||||
}
|
||||
|
||||
break;
|
||||
} while(--tries > 0);
|
||||
|
||||
return tries > 0;
|
||||
}
|
||||
|
||||
bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size)
|
||||
{
|
||||
const u8 devAddr = i2cDevTable[devId].devAddr;
|
||||
I2cRegs *const regs = i2cGetBusRegsBase(i2cDevTable[devId].busId);
|
||||
|
||||
|
||||
if(!i2cStartTransfer(devAddr, regAddr, true, regs)) return false;
|
||||
|
||||
while(--size)
|
||||
{
|
||||
regs->I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIR_READ | I2C_ACK;
|
||||
i2cWaitBusyIrq(regs);
|
||||
*out++ = regs->I2C_DATA;
|
||||
}
|
||||
|
||||
// Last byte transfer.
|
||||
regs->I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIR_READ | I2C_STOP;
|
||||
i2cWaitBusyIrq(regs);
|
||||
*out = regs->I2C_DATA;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool I2C_writeRegBuf(I2cDevice devId, u8 regAddr, const u8 *in, u32 size)
|
||||
{
|
||||
const u8 devAddr = i2cDevTable[devId].devAddr;
|
||||
I2cRegs *const regs = i2cGetBusRegsBase(i2cDevTable[devId].busId);
|
||||
|
||||
|
||||
if(!i2cStartTransfer(devAddr, regAddr, false, regs)) return false;
|
||||
|
||||
while(--size)
|
||||
{
|
||||
regs->I2C_DATA = *in++;
|
||||
regs->I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIR_WRITE;
|
||||
i2cWaitBusyIrq(regs);
|
||||
if(!i2cCheckAck(regs)) return false;
|
||||
}
|
||||
|
||||
// Last byte transfer.
|
||||
regs->I2C_DATA = *in;
|
||||
regs->I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIR_WRITE | I2C_STOP;
|
||||
i2cWaitBusyIrq(regs);
|
||||
if(!i2cCheckAck(regs)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
u8 I2C_readReg(I2cDevice devId, u8 regAddr)
|
||||
{
|
||||
u8 data;
|
||||
if(!I2C_readRegBuf(devId, regAddr, &data, 1)) return 0xFF;
|
||||
return data;
|
||||
}
|
||||
|
||||
bool I2C_writeReg(I2cDevice devId, u8 regAddr, u8 data)
|
||||
{
|
||||
return I2C_writeRegBuf(devId, regAddr, &data, 1);
|
||||
}
|
||||
|
||||
bool I2C_writeRegIntSafe(I2cDevice devId, u8 regAddr, u8 data)
|
||||
{
|
||||
const u8 devAddr = i2cDevTable[devId].devAddr;
|
||||
I2cRegs *const regs = i2cGetBusRegsBase(i2cDevTable[devId].busId);
|
||||
|
||||
|
||||
u32 tries = 8;
|
||||
do
|
||||
{
|
||||
while(regs->I2C_CNT & I2C_ENABLE);
|
||||
|
||||
// Select device and start.
|
||||
regs->I2C_DATA = devAddr;
|
||||
regs->I2C_CNT = I2C_ENABLE | I2C_DIR_WRITE | I2C_START;
|
||||
while(regs->I2C_CNT & I2C_ENABLE);
|
||||
if(!i2cCheckAck(regs)) continue;
|
||||
|
||||
// Select register.
|
||||
regs->I2C_DATA = regAddr;
|
||||
regs->I2C_CNT = I2C_ENABLE | I2C_DIR_WRITE;
|
||||
while(regs->I2C_CNT & I2C_ENABLE);
|
||||
if(!i2cCheckAck(regs)) continue;
|
||||
|
||||
break;
|
||||
} while(--tries > 0);
|
||||
|
||||
if(tries == 0) return false;
|
||||
|
||||
regs->I2C_DATA = data;
|
||||
regs->I2C_CNT = I2C_ENABLE | I2C_DIR_WRITE | I2C_STOP;
|
||||
while(regs->I2C_CNT & I2C_ENABLE);
|
||||
if(!i2cCheckAck(regs)) return false;
|
||||
|
||||
return true;
|
||||
}
|
|
@ -1,246 +0,0 @@
|
|||
/*
|
||||
* 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/interrupt.h"
|
||||
#include "mmio.h"
|
||||
#include "arm.h"
|
||||
#include "arm11/hardware/cfg11.h"
|
||||
|
||||
|
||||
// Level high active keeps firing until acknowledged (on the periphal side).
|
||||
// Rising edge sensitive only fires on rising edges.
|
||||
#define ICONF_RSVD (0u) // Unused/reserved.
|
||||
#define ICONF_L_NN (0u) // Level high active, N-N software model.
|
||||
#define ICONF_L_1N (1u) // Level high active, 1-N software model.
|
||||
#define ICONF_E_NN (2u) // Rising edge sinsitive, N-N software model.
|
||||
#define ICONF_E_1N (3u) // Rising edge sinsitive, 1-N software model.
|
||||
#define MAKE_ICONF(c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15) \
|
||||
((c15)<<30 | (c14)<<28 | (c13)<<26 | (c12)<<24 | (c11)<<22 | \
|
||||
(c10)<<20 | (c9)<<18 | (c8)<<16 | (c7)<<14 | (c6)<<12 | \
|
||||
(c5)<<10 | (c4)<<8 | (c3)<<6 | (c2)<<4 | (c1)<<2 | (c0))
|
||||
|
||||
|
||||
// First 32 interrupts are private to each core (4 * 32).
|
||||
// 96 external interrupts (total 128).
|
||||
IrqIsr irqIsrTable[224] = {0};
|
||||
|
||||
|
||||
|
||||
// Per core interrupts.
|
||||
static void configPrivateInterrupts(void)
|
||||
{
|
||||
// Disable first 32 interrupts.
|
||||
// Interrupts 0-15 cant be disabled.
|
||||
REGs_GIC_DIST_ENABLE_CLEAR[0] = 0xFFFFFFFFu;
|
||||
|
||||
// Set first 32 interrupts to inactive state.
|
||||
// Interrupt 0-15 can't be set to inactive.
|
||||
REGs_GIC_DIST_PENDING_CLEAR[0] = 0xFFFFFFFFu;
|
||||
|
||||
// Set first 32 interrupts to lowest priority.
|
||||
for(u32 i = 0; i < 8; i++) REGs_GIC_DIST_PRI[i] = 0xF0F0F0F0u;
|
||||
|
||||
// Interrupt target 0-31 can't be changed.
|
||||
|
||||
// Kernel11 config.
|
||||
// Interrupts 0-15.
|
||||
REGs_GIC_DIST_CONFIG[0] = MAKE_ICONF(ICONF_E_NN, ICONF_E_NN, ICONF_E_NN, ICONF_E_NN, // 0-3
|
||||
ICONF_E_NN, ICONF_E_NN, ICONF_E_NN, ICONF_E_NN, // 4-7
|
||||
ICONF_E_NN, ICONF_E_NN, ICONF_E_NN, ICONF_E_NN, // 8-11
|
||||
ICONF_E_NN, ICONF_E_NN, ICONF_E_NN, ICONF_E_NN); // 12-15
|
||||
// Interrupts 16-31.
|
||||
REGs_GIC_DIST_CONFIG[1] = MAKE_ICONF(ICONF_RSVD, ICONF_RSVD, ICONF_RSVD, ICONF_RSVD, // 16-19
|
||||
ICONF_RSVD, ICONF_RSVD, ICONF_RSVD, ICONF_RSVD, // 20-23
|
||||
ICONF_RSVD, ICONF_RSVD, ICONF_RSVD, ICONF_RSVD, // 24-27
|
||||
ICONF_RSVD, ICONF_E_NN, ICONF_E_NN, ICONF_RSVD); // 28-31
|
||||
}
|
||||
|
||||
static void configExternalInterrupts(void)
|
||||
{
|
||||
// Kernel11 config.
|
||||
/*static const u32 iconfTable[6] =
|
||||
{
|
||||
// Interrupts 32-47.
|
||||
MAKE_ICONF(ICONF_L_1N, ICONF_L_1N, ICONF_L_1N, ICONF_L_1N, // 32-35
|
||||
ICONF_E_1N, ICONF_L_1N, ICONF_RSVD, ICONF_RSVD, // 36-39
|
||||
ICONF_L_1N, ICONF_L_1N, ICONF_L_1N, ICONF_L_1N, // 40-43
|
||||
ICONF_L_1N, ICONF_L_1N, ICONF_RSVD, ICONF_RSVD), // 44-47
|
||||
// Interrupts 48-63.
|
||||
MAKE_ICONF(ICONF_L_1N, ICONF_L_1N, ICONF_L_1N, ICONF_L_1N, // 48-51
|
||||
ICONF_L_1N, ICONF_L_1N, ICONF_L_1N, ICONF_L_1N, // 52-55
|
||||
ICONF_L_1N, ICONF_L_1N, ICONF_L_1N, ICONF_L_1N, // 56-59
|
||||
ICONF_RSVD, ICONF_RSVD, ICONF_RSVD, ICONF_RSVD), // 60-63
|
||||
// Interrupts 64-79.
|
||||
MAKE_ICONF(ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, // 64-67
|
||||
ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, ICONF_RSVD, // 68-71
|
||||
ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, // 72-75
|
||||
ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, ICONF_L_1N), // 76-79
|
||||
// Interrupts 80-95.
|
||||
MAKE_ICONF(ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, // 80-83
|
||||
ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, // 84-87
|
||||
ICONF_L_1N, ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, // 88-91
|
||||
ICONF_RSVD, ICONF_RSVD, ICONF_RSVD, ICONF_E_1N), // 92-95
|
||||
// Interrupts 96-111.
|
||||
MAKE_ICONF(ICONF_E_1N, ICONF_E_1N, ICONF_RSVD, ICONF_RSVD, // 96-99
|
||||
ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, ICONF_RSVD, // 100-103
|
||||
ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, // 104-107
|
||||
ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, ICONF_E_1N), // 108-111
|
||||
// Interrupts 112-127.
|
||||
MAKE_ICONF(ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, // 112-115
|
||||
ICONF_E_1N, ICONF_E_1N, ICONF_L_1N, ICONF_L_1N, // 116-119
|
||||
ICONF_E_1N, ICONF_L_1N, ICONF_L_1N, ICONF_L_1N, // 120-123
|
||||
ICONF_L_1N, ICONF_L_1N, ICONF_RSVD, ICONF_RSVD) // 124-127
|
||||
};*/
|
||||
// Modified.
|
||||
static const u32 iconfTable[6] =
|
||||
{
|
||||
// Interrupts 32-47.
|
||||
MAKE_ICONF(ICONF_L_1N, ICONF_L_1N, ICONF_L_1N, ICONF_L_1N, // 32-35
|
||||
ICONF_E_1N, ICONF_L_1N, ICONF_RSVD, ICONF_RSVD, // 36-39
|
||||
ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, // 40-43
|
||||
ICONF_E_1N, ICONF_E_1N, ICONF_RSVD, ICONF_RSVD), // 44-47
|
||||
// Interrupts 48-63.
|
||||
MAKE_ICONF(ICONF_L_1N, ICONF_L_1N, ICONF_L_1N, ICONF_L_1N, // 48-51
|
||||
ICONF_L_1N, ICONF_L_1N, ICONF_L_1N, ICONF_L_1N, // 52-55
|
||||
ICONF_L_1N, ICONF_L_1N, ICONF_L_1N, ICONF_L_1N, // 56-59
|
||||
ICONF_RSVD, ICONF_RSVD, ICONF_RSVD, ICONF_RSVD), // 60-63
|
||||
// Interrupts 64-79.
|
||||
MAKE_ICONF(ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, // 64-67
|
||||
ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, ICONF_RSVD, // 68-71
|
||||
ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, // 72-75
|
||||
ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, ICONF_L_1N), // 76-79
|
||||
// Interrupts 80-95.
|
||||
MAKE_ICONF(ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, // 80-83
|
||||
ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, // 84-87
|
||||
ICONF_L_1N, ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, // 88-91
|
||||
ICONF_RSVD, ICONF_RSVD, ICONF_RSVD, ICONF_E_1N), // 92-95
|
||||
// Interrupts 96-111.
|
||||
MAKE_ICONF(ICONF_E_1N, ICONF_E_1N, ICONF_RSVD, ICONF_RSVD, // 96-99
|
||||
ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, ICONF_RSVD, // 100-103
|
||||
ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, // 104-107
|
||||
ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, ICONF_E_1N), // 108-111
|
||||
// Interrupts 112-127.
|
||||
MAKE_ICONF(ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, ICONF_E_1N, // 112-115
|
||||
ICONF_E_1N, ICONF_E_1N, ICONF_L_1N, ICONF_L_1N, // 116-119
|
||||
ICONF_E_1N, ICONF_L_1N, ICONF_L_1N, ICONF_L_1N, // 120-123
|
||||
ICONF_L_1N, ICONF_L_1N, ICONF_RSVD, ICONF_RSVD) // 124-127
|
||||
};
|
||||
|
||||
iomemcpy(®s_GIC_DIST_CONFIG[2], iconfTable, 24);
|
||||
}
|
||||
|
||||
// Note: Core 0 must execute this last.
|
||||
void IRQ_init(void)
|
||||
{
|
||||
REG_GIC_DIST_CTRL = 0; // Disable the global interrupt distributor.
|
||||
|
||||
configPrivateInterrupts();
|
||||
|
||||
if(__getCpuId() == 0)
|
||||
{
|
||||
// Disable the remaining 96 interrupts.
|
||||
// Set the remaining 96 pending interrupts to inactive state.
|
||||
for(u32 i = 1; i < 4; i++)
|
||||
{
|
||||
REGs_GIC_DIST_ENABLE_CLEAR[i] = 0xFFFFFFFFu;
|
||||
REGs_GIC_DIST_PENDING_CLEAR[i] = 0xFFFFFFFFu;
|
||||
}
|
||||
|
||||
// Set the remaining 96 interrupts to lowest priority.
|
||||
// Set the remaining 96 interrupts to target no CPU.
|
||||
for(u32 i = 8; i < 32; i++)
|
||||
{
|
||||
REGs_GIC_DIST_PRI[i] = 0xF0F0F0F0u;
|
||||
REGs_GIC_DIST_TARGET[i] = 0;
|
||||
}
|
||||
|
||||
configExternalInterrupts();
|
||||
|
||||
REG_GIC_DIST_CTRL = 1; // Enable the global interrupt distributor.
|
||||
}
|
||||
|
||||
|
||||
REG_GIC_CPU_PRIMASK = 0xF0; // Mask no interrupt.
|
||||
REG_GIC_CPU_BINPOINT = 3; // All priority bits are compared for pre-emption.
|
||||
REG_GIC_CPU_CTRL = 1; // Enable the interrupt interface for this CPU.
|
||||
|
||||
REG_CFG11_FIQ_MASK = FIQ_MASK_CPU3 | FIQ_MASK_CPU2 | FIQ_MASK_CPU1 | FIQ_MASK_CPU0; // Disable FIQs.
|
||||
}
|
||||
|
||||
void IRQ_registerIsr(Interrupt id, u8 prio, u8 cpuMask, IrqIsr isr)
|
||||
{
|
||||
const u32 cpuId = __getCpuId();
|
||||
if(!cpuMask) cpuMask = 1u<<cpuId;
|
||||
|
||||
const u32 oldState = enterCriticalSection();
|
||||
|
||||
irqIsrTable[(id < 32 ? 32 * cpuId + id : 96u + id)] = isr;
|
||||
|
||||
// Priority
|
||||
u32 shift = (id % 4 * 8) + 4;
|
||||
u32 tmp = REGs_GIC_DIST_PRI[id / 4] & ~(0xFu<<shift);
|
||||
REGs_GIC_DIST_PRI[id / 4] = tmp | (u32)prio<<shift;
|
||||
|
||||
// Target
|
||||
shift = id % 4 * 8;
|
||||
tmp = REGs_GIC_DIST_TARGET[id / 4] & ~(0xFu<<shift);
|
||||
REGs_GIC_DIST_TARGET[id / 4] = tmp | (u32)cpuMask<<shift;
|
||||
|
||||
// Enable it.
|
||||
REGs_GIC_DIST_ENABLE_SET[id / 32] = 1u<<(id % 32);
|
||||
|
||||
leaveCriticalSection(oldState);
|
||||
}
|
||||
|
||||
void IRQ_enable(Interrupt id)
|
||||
{
|
||||
REGs_GIC_DIST_ENABLE_SET[id / 32] = 1u<<(id % 32);
|
||||
}
|
||||
|
||||
void IRQ_disable(Interrupt id)
|
||||
{
|
||||
REGs_GIC_DIST_ENABLE_CLEAR[id / 32] = 1u<<(id % 32);
|
||||
}
|
||||
|
||||
void IRQ_softwareInterrupt(Interrupt id, u8 cpuMask)
|
||||
{
|
||||
REG_GIC_DIST_SOFTINT = (u32)cpuMask<<16 | id;
|
||||
}
|
||||
|
||||
void IRQ_setPriority(Interrupt id, u8 prio)
|
||||
{
|
||||
const u32 oldState = enterCriticalSection();
|
||||
|
||||
const u32 shift = (id % 4 * 8) + 4;
|
||||
u32 tmp = REGs_GIC_DIST_PRI[id / 4] & ~(0xFu<<shift);
|
||||
REGs_GIC_DIST_PRI[id / 4] = tmp | (u32)prio<<shift;
|
||||
|
||||
leaveCriticalSection(oldState);
|
||||
}
|
||||
|
||||
void IRQ_unregisterIsr(Interrupt id)
|
||||
{
|
||||
const u32 oldState = enterCriticalSection();
|
||||
|
||||
REGs_GIC_DIST_ENABLE_CLEAR[id / 32] = 1u<<(id % 32);
|
||||
|
||||
irqIsrTable[(id < 32 ? 32 * __getCpuId() + id : 96u + id)] = (IrqIsr)NULL;
|
||||
|
||||
leaveCriticalSection(oldState);
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
#include "types.h"
|
||||
#include "arm11/hardware/lcd.h"
|
||||
#include "arm11/hardware/i2c.h"
|
||||
#include "arm11/hardware/timer.h"
|
||||
|
||||
|
||||
#define LCD_BACKLIGHT_TIMEOUT (10u)
|
||||
|
||||
|
||||
|
||||
u8 LCDI2C_readReg(u8 lcd, LcdI2cReg reg)
|
||||
{
|
||||
u8 buf[2];
|
||||
const u8 dev = (lcd == 0 ? I2C_DEV_LCD0 : I2C_DEV_LCD1);
|
||||
|
||||
I2C_writeReg(dev, LCD_I2C_REG_READ_ADDR, reg);
|
||||
I2C_readRegBuf(dev, LCD_I2C_REG_READ_ADDR, buf, 2);
|
||||
|
||||
return buf[1];
|
||||
}
|
||||
|
||||
void LCDI2C_writeReg(u8 lcd, LcdI2cReg reg, u8 data)
|
||||
{
|
||||
const u8 dev = (lcd == 0 ? I2C_DEV_LCD0 : I2C_DEV_LCD1);
|
||||
|
||||
I2C_writeReg(dev, reg, data);
|
||||
}
|
||||
|
||||
void LCDI2C_init(void)
|
||||
{
|
||||
const u16 revs = LCDI2C_getRevisions();
|
||||
|
||||
// Top screen
|
||||
if(revs & 0xFFu) LCDI2C_writeReg(0, LCD_I2C_REG_RST_STATUS, LCD_REG_RST_STATUS_NONE);
|
||||
else
|
||||
{
|
||||
LCDI2C_writeReg(0, LCD_I2C_REG_UNK11, LCD_REG_UNK11_UNK10);
|
||||
LCDI2C_writeReg(0, LCD_I2C_REG_HS_SERIAL, LCD_REG_HS_SERIAL_ON);
|
||||
}
|
||||
|
||||
// Bottom screen
|
||||
if(revs>>8) LCDI2C_writeReg(1, LCD_I2C_REG_RST_STATUS, LCD_REG_RST_STATUS_NONE);
|
||||
else LCDI2C_writeReg(1, LCD_I2C_REG_UNK11, LCD_REG_UNK11_UNK10);
|
||||
|
||||
LCDI2C_writeReg(0, LCD_I2C_REG_STATUS, LCD_REG_STATUS_OK); // Initialize status flag.
|
||||
LCDI2C_writeReg(1, LCD_I2C_REG_STATUS, LCD_REG_STATUS_OK); // Initialize status flag.
|
||||
LCDI2C_writeReg(0, LCD_I2C_REG_POWER, LCD_REG_POWER_ON); // Power on LCD.
|
||||
LCDI2C_writeReg(1, LCD_I2C_REG_POWER, LCD_REG_POWER_ON); // Power on LCD.
|
||||
}
|
||||
|
||||
void LCDI2C_waitBacklightsOn(void)
|
||||
{
|
||||
const u16 revs = LCDI2C_getRevisions();
|
||||
|
||||
if((revs & 0xFFu) == 0 || (revs>>8) == 0)
|
||||
{
|
||||
// Bug workaround for early LCD driver revisions?
|
||||
TIMER_sleepMs(150);
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 i = 0;
|
||||
do
|
||||
{
|
||||
const u8 top = LCDI2C_readReg(0, LCD_I2C_REG_BL_STATUS);
|
||||
const u8 bot = LCDI2C_readReg(1, LCD_I2C_REG_BL_STATUS);
|
||||
|
||||
if(top == LCD_REG_BL_STATUS_ON && bot == LCD_REG_BL_STATUS_ON) break;
|
||||
|
||||
TIMER_sleepTicks(TIMER_FREQ(1, 1000) * 33.333f);
|
||||
} while(++i < LCD_BACKLIGHT_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
u16 LCDI2C_getRevisions(void)
|
||||
{
|
||||
static bool lcdRevsRead = false;
|
||||
static u16 lcdRevs;
|
||||
|
||||
if(!lcdRevsRead)
|
||||
{
|
||||
lcdRevsRead = true;
|
||||
|
||||
lcdRevs = LCDI2C_readReg(0, LCD_I2C_REG_REVISION) |
|
||||
LCDI2C_readReg(1, LCD_I2C_REG_REVISION)<<8;
|
||||
}
|
||||
|
||||
return lcdRevs;
|
||||
}
|
|
@ -1,369 +0,0 @@
|
|||
#include <string.h>
|
||||
#include "types.h"
|
||||
#include "hardware/lgy.h"
|
||||
#include "hardware/pxi.h"
|
||||
#include "ipc_handler.h"
|
||||
#include "arm11/hardware/hid.h"
|
||||
#include "arm11/hardware/interrupt.h"
|
||||
#include "fs.h"
|
||||
#include "hardware/cache.h"
|
||||
#include "arm11/hardware/pdn.h"
|
||||
#include "arm11/hardware/mcu.h"
|
||||
#include "arm11/hardware/lgyfb.h"
|
||||
#include "arm11/fmt.h"
|
||||
//#include "arm11/gba_save_type_db.h"
|
||||
|
||||
|
||||
#define LGY_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x41100)
|
||||
#define REG_LGY_MODE *(( vu16*)(LGY_REGS_BASE + 0x00))
|
||||
#define REG_LGY_SLEEP *(( vu16*)(LGY_REGS_BASE + 0x04))
|
||||
#define REG_LGY_UNK *((const vu16*)(LGY_REGS_BASE + 0x08)) // IRQ related?
|
||||
#define REG_LGY_PADCNT *((const vu16*)(LGY_REGS_BASE + 0x0A)) // ARM7 "KEYCNT"
|
||||
#define REG_LGY_PAD_SEL *(( vu16*)(LGY_REGS_BASE + 0x10)) // Select which keys to override.
|
||||
#define REG_LGY_PAD_VAL *(( vu16*)(LGY_REGS_BASE + 0x12)) // Override value.
|
||||
#define REG_LGY_GPIO_SEL *(( vu16*)(LGY_REGS_BASE + 0x14)) // Select which GPIOs to override.
|
||||
#define REG_LGY_GPIO_VAL *(( vu16*)(LGY_REGS_BASE + 0x16)) // Override value.
|
||||
#define REG_LGY_UNK2 *(( vu8*)(LGY_REGS_BASE + 0x18)) // DSi gamecard detection select?
|
||||
#define REG_LGY_UNK3 *(( vu8*)(LGY_REGS_BASE + 0x19)) // DSi gamecard detection value?
|
||||
#define REG_LGY_UNK4 *((const vu8*)(LGY_REGS_BASE + 0x20)) // Some legacy status bits?
|
||||
|
||||
|
||||
|
||||
static void lgySleepIrqHandler(u32 intSource)
|
||||
{
|
||||
if(intSource == IRQ_LGY_SLEEP)
|
||||
{
|
||||
REG_HID_PADCNT = REG_LGY_PADCNT;
|
||||
}
|
||||
else // IRQ_HID_PADCNT
|
||||
{
|
||||
// TODO: Synchronize with LCD VBlank.
|
||||
REG_HID_PADCNT = 0;
|
||||
REG_LGY_SLEEP |= 1u; // Acknowledge and wakeup.
|
||||
}
|
||||
}
|
||||
|
||||
static Result loadGbaRom(const char *const path, u32 *const rsOut)
|
||||
{
|
||||
Result res;
|
||||
FHandle f;
|
||||
if((res = fOpen(&f, path, FA_OPEN_EXISTING | FA_READ)) == RES_OK)
|
||||
{
|
||||
u32 romSize;
|
||||
if((romSize = fSize(f)) <= MAX_ROM_SIZE)
|
||||
{
|
||||
u8 *ptr = (u8*)ROM_LOC;
|
||||
u32 read;
|
||||
while((res = fRead(f, ptr, 0x100000u, &read)) == RES_OK && read == 0x100000u)
|
||||
ptr += 0x100000u;
|
||||
|
||||
if(res == RES_OK)
|
||||
{
|
||||
*rsOut = romSize;
|
||||
// Pad ROM area with "open bus" value.
|
||||
memset((void*)(ROM_LOC + romSize), 0xFFFFFFFFu, MAX_ROM_SIZE - romSize);
|
||||
}
|
||||
}
|
||||
else res = RES_ROM_TOO_BIG;
|
||||
|
||||
fClose(f);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static u16 checkSaveOverride(u32 gameCode)
|
||||
{
|
||||
if((gameCode & 0xFFu) == 'F') // Classic NES Series.
|
||||
{
|
||||
return SAVE_TYPE_EEPROM_8k;
|
||||
}
|
||||
|
||||
static const struct
|
||||
{
|
||||
alignas(4) char gameCode[4];
|
||||
u16 saveType;
|
||||
} overrideLut[] =
|
||||
{
|
||||
{"\0\0\0\0", SAVE_TYPE_SRAM_256k}, // Homebrew. TODO: Set WAITCNT to 0x4014?
|
||||
{"GMB\0", SAVE_TYPE_SRAM_256k}, // Goomba Color (Homebrew).
|
||||
{"AA2\0", SAVE_TYPE_EEPROM_64k}, // Super Mario Advance 2.
|
||||
{"A3A\0", SAVE_TYPE_EEPROM_64k}, // Super Mario Advance 3.
|
||||
};
|
||||
|
||||
for(u32 i = 0; i < sizeof(overrideLut) / sizeof(*overrideLut); i++)
|
||||
{
|
||||
// Compare Game Code without region.
|
||||
if((gameCode & 0xFFFFFFu) == *((u32*)overrideLut[i].gameCode))
|
||||
{
|
||||
return overrideLut[i].saveType;
|
||||
}
|
||||
}
|
||||
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
// Code based on: https://github.com/Gericom/GBARunner2/blob/master/arm9/source/save/Save.vram.cpp
|
||||
static u16 tryDetectSaveType(u32 romSize)
|
||||
{
|
||||
const u32 *romPtr = (u32*)ROM_LOC;
|
||||
u16 saveType;
|
||||
if((saveType = checkSaveOverride(romPtr[0xAC / 4])) != 0xFF)
|
||||
{
|
||||
debug_printf("Game Code in override list. Using save type %" PRIu16 ".\n", saveType);
|
||||
return saveType;
|
||||
}
|
||||
|
||||
romPtr += 0xE4 / 4; // Skip headers.
|
||||
saveType = SAVE_TYPE_NONE;
|
||||
for(; romPtr < (u32*)(ROM_LOC + romSize); romPtr++)
|
||||
{
|
||||
u32 tmp = *romPtr;
|
||||
|
||||
// "EEPR" "FLAS" "SRAM"
|
||||
if(tmp == 0x52504545u || tmp == 0x53414C46u || tmp == 0x4D415253u)
|
||||
{
|
||||
static const struct
|
||||
{
|
||||
const char *str;
|
||||
u16 saveType;
|
||||
} saveTypeLut[25] =
|
||||
{
|
||||
// EEPROM
|
||||
{"EEPROM_V111", SAVE_TYPE_EEPROM_8k}, // Actually EEPROM 4k.
|
||||
{"EEPROM_V120", SAVE_TYPE_EEPROM_8k}, // Confirmed.
|
||||
{"EEPROM_V121", SAVE_TYPE_EEPROM_64k}, // Confirmed.
|
||||
{"EEPROM_V122", SAVE_TYPE_EEPROM_8k}, // Confirmed. Except Super Mario Advance 2/3.
|
||||
{"EEPROM_V124", SAVE_TYPE_EEPROM_64k}, // Confirmed.
|
||||
{"EEPROM_V125", SAVE_TYPE_EEPROM_8k}, // Confirmed.
|
||||
{"EEPROM_V126", SAVE_TYPE_EEPROM_8k}, // Confirmed.
|
||||
|
||||
// FLASH
|
||||
// Assume they all have RTC.
|
||||
{"FLASH_V120", SAVE_TYPE_FLASH_512k_PSC_RTC},
|
||||
{"FLASH_V121", SAVE_TYPE_FLASH_512k_PSC_RTC},
|
||||
{"FLASH_V123", SAVE_TYPE_FLASH_512k_PSC_RTC},
|
||||
{"FLASH_V124", SAVE_TYPE_FLASH_512k_PSC_RTC},
|
||||
{"FLASH_V125", SAVE_TYPE_FLASH_512k_PSC_RTC},
|
||||
{"FLASH_V126", SAVE_TYPE_FLASH_512k_PSC_RTC},
|
||||
{"FLASH512_V130", SAVE_TYPE_FLASH_512k_PSC_RTC},
|
||||
{"FLASH512_V131", SAVE_TYPE_FLASH_512k_PSC_RTC},
|
||||
{"FLASH512_V133", SAVE_TYPE_FLASH_512k_PSC_RTC},
|
||||
{"FLASH1M_V102", SAVE_TYPE_FLASH_1m_MRX_RTC},
|
||||
{"FLASH1M_V103", SAVE_TYPE_FLASH_1m_MRX_RTC},
|
||||
|
||||
// FRAM & SRAM
|
||||
{"SRAM_F_V100", SAVE_TYPE_SRAM_256k},
|
||||
{"SRAM_F_V102", SAVE_TYPE_SRAM_256k},
|
||||
{"SRAM_F_V103", SAVE_TYPE_SRAM_256k},
|
||||
|
||||
{"SRAM_V110", SAVE_TYPE_SRAM_256k},
|
||||
{"SRAM_V111", SAVE_TYPE_SRAM_256k},
|
||||
{"SRAM_V112", SAVE_TYPE_SRAM_256k},
|
||||
{"SRAM_V113", SAVE_TYPE_SRAM_256k}
|
||||
};
|
||||
|
||||
for(u32 i = 0; i < 25; i++)
|
||||
{
|
||||
const char *const str = saveTypeLut[i].str;
|
||||
u16 tmpSaveType = saveTypeLut[i].saveType;
|
||||
|
||||
if(memcmp(romPtr, str, strlen(str)) == 0)
|
||||
{
|
||||
if(tmpSaveType == SAVE_TYPE_EEPROM_8k || tmpSaveType == SAVE_TYPE_EEPROM_64k)
|
||||
{
|
||||
// If ROM bigger than 16 MiB --> SAVE_TYPE_EEPROM_8k_2 or SAVE_TYPE_EEPROM_64k_2.
|
||||
if(romSize > 0x1000000) tmpSaveType++;
|
||||
}
|
||||
saveType = tmpSaveType;
|
||||
debug_printf("Detected SDK save type '%s'.\n", str);
|
||||
goto saveTypeFound;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
saveTypeFound:
|
||||
|
||||
return saveType;
|
||||
}
|
||||
|
||||
/*static u16 getSaveTypeFromTable(void)
|
||||
{
|
||||
const u32 gameCode = *(u32*)(ROM_LOC + 0xAC) & ~0xFF000000u;
|
||||
|
||||
u16 saveType = SAVE_TYPE_NONE;
|
||||
for(u32 i = 0; i < sizeof(saveTypeLut) / sizeof(*saveTypeLut); i++)
|
||||
{
|
||||
// Save type in last byte.
|
||||
const u32 entry = *((u32*)&saveTypeLut[i]);
|
||||
if((entry & ~0xFF000000u) == gameCode)
|
||||
{
|
||||
saveType = entry>>24;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
debug_printf("Using save type 0x%" PRIX16 ".\n", saveType);
|
||||
|
||||
return saveType;
|
||||
}*/
|
||||
|
||||
static void setupFcramForGbaMode(void)
|
||||
{
|
||||
// FCRAM reset and clock disable.
|
||||
flushDCache();
|
||||
// TODO: Unmap FCRAM.
|
||||
while(!REG_LGY_MODE); // Wait until legacy mode is ready.
|
||||
*((vu32*)0x10201000) &= ~1u; // Some kind of bug fix for the GBA cart emu?
|
||||
REG_PDN_FCRAM_CNT = 0; // Set reset low (active).
|
||||
REG_PDN_FCRAM_CNT = PDN_FCRAM_CNT_RST; // Take it out of reset.
|
||||
while(REG_PDN_FCRAM_CNT & PDN_FCRAM_CNT_CLK_E_ACK); // Wait until clock is disabled.
|
||||
}
|
||||
|
||||
Result LGY_prepareGbaMode(bool biosIntro, char *const romPath)
|
||||
{
|
||||
// Load the ROM image.
|
||||
u32 romSize;
|
||||
Result res = loadGbaRom(romPath, &romSize);
|
||||
if(res != RES_OK) return res;
|
||||
|
||||
// Try to detect the save type.
|
||||
const u16 saveType = tryDetectSaveType(romSize);
|
||||
//const u16 saveType = getSaveTypeFromTable();
|
||||
|
||||
// Prepare ARM9 for GBA mode + settings and save loading.
|
||||
const u32 romPathLen = strlen(romPath);
|
||||
strcpy(romPath + romPathLen - 4, ".sav");
|
||||
|
||||
u32 cmdBuf[4];
|
||||
cmdBuf[0] = (u32)romPath;
|
||||
cmdBuf[1] = romPathLen + 1;
|
||||
cmdBuf[2] = biosIntro;
|
||||
cmdBuf[3] = saveType;
|
||||
res = PXI_sendCmd(IPC_CMD9_PREPARE_GBA, cmdBuf, 4);
|
||||
if(res != RES_OK) return res;
|
||||
|
||||
// Setup GBA Real-Time Clock.
|
||||
GbaRtc rtc;
|
||||
MCU_getRTCTime((u8*)&rtc);
|
||||
rtc.time = __builtin_bswap32(rtc.time)>>8;
|
||||
rtc.date = __builtin_bswap32(rtc.date)>>8;
|
||||
// TODO: Do we need to set day of week?
|
||||
LGY_setGbaRtc(rtc);
|
||||
|
||||
// Setup Legacy Framebuffer.
|
||||
LGYFB_init();
|
||||
|
||||
// Setup FCRAM for GBA mode.
|
||||
setupFcramForGbaMode();
|
||||
|
||||
// Setup IRQ handlers and sleep mode handling.
|
||||
REG_LGY_SLEEP = 1u<<15;
|
||||
IRQ_registerIsr(IRQ_LGY_SLEEP, 14, 0, lgySleepIrqHandler);
|
||||
IRQ_registerIsr(IRQ_HID_PADCNT, 14, 0, lgySleepIrqHandler);
|
||||
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
Result LGY_setGbaRtc(const GbaRtc rtc)
|
||||
{
|
||||
return PXI_sendCmd(IPC_CMD9_SET_GBA_RTC, (u32*)&rtc, sizeof(GbaRtc) / 4);
|
||||
}
|
||||
|
||||
Result LGY_getGbaRtc(GbaRtc *const out)
|
||||
{
|
||||
const u32 cmdBuf[2] = {(u32)out, sizeof(GbaRtc)};
|
||||
return PXI_sendCmd(IPC_CMD9_GET_GBA_RTC, cmdBuf, 2);
|
||||
}
|
||||
|
||||
void LGY_switchMode(void)
|
||||
{
|
||||
REG_LGY_MODE = LGY_MODE_START;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
#include "arm11/hardware/gx.h"
|
||||
#include "arm11/hardware/gpu_regs.h"
|
||||
void debugTests(void)
|
||||
{
|
||||
const u32 kDown = hidKeysDown();
|
||||
|
||||
// Print GBA RTC date/time.
|
||||
if(kDown & KEY_X)
|
||||
{
|
||||
GbaRtc rtc; LGY_getGbaRtc(&rtc);
|
||||
ee_printf("RTC: %02X.%02X.%04X %02X:%02X:%02X\n", rtc.d, rtc.mon, rtc.y + 0x2000u, rtc.h, rtc.min, rtc.s);
|
||||
|
||||
/*static u8 filter = 1;
|
||||
filter ^= 1;
|
||||
u32 texEnvSource = 0x000F000F;
|
||||
u32 texEnvCombiner = 0x00000000;
|
||||
if(filter == 1)
|
||||
{
|
||||
texEnvSource = 0x00FF00FFu;
|
||||
texEnvCombiner = 0x00010001u;
|
||||
}
|
||||
REG_GX_P3D(GPUREG_TEXENV1_SOURCE) = texEnvSource;
|
||||
REG_GX_P3D(GPUREG_TEXENV1_COMBINER) = texEnvCombiner;*/
|
||||
|
||||
// Trigger Game Boy Player enhancements.
|
||||
// Needs to be done on the Game Boy Player logo screen.
|
||||
// 2 frames nothing pressed and 1 frame all D-Pad buttons pressed.
|
||||
/*REG_LGY_PAD_SEL = 0x1FFF; // Override all buttons.
|
||||
static u8 gbp = 2;
|
||||
if(gbp > 0)
|
||||
{
|
||||
REG_LGY_PAD_VAL = 0x1FFF; // Force all buttons not pressed.
|
||||
gbp--;
|
||||
}
|
||||
else
|
||||
{
|
||||
REG_LGY_PAD_VAL = 0x1F0F; // All D-Pad buttons pressed.
|
||||
gbp = 2;
|
||||
}*/
|
||||
}
|
||||
//else REG_LGY_PAD_SEL = 0; // Stop overriding buttons.
|
||||
if(kDown & KEY_Y) LGYFB_dbgDumpFrame();
|
||||
}
|
||||
#endif
|
||||
|
||||
void LGY_handleEvents(void)
|
||||
{
|
||||
// Override D-Pad if Circle-Pad is used.
|
||||
const u32 kHeld = hidKeysHeld();
|
||||
u16 padSel;
|
||||
if(kHeld & KEY_CPAD_MASK)
|
||||
{
|
||||
REG_LGY_PAD_VAL = (kHeld>>24) ^ KEY_DPAD_MASK;
|
||||
padSel = KEY_DPAD_MASK;
|
||||
}
|
||||
else padSel = 0;
|
||||
REG_LGY_PAD_SEL = padSel;
|
||||
|
||||
#ifndef NDEBUG
|
||||
debugTests();
|
||||
#endif
|
||||
|
||||
LGYFB_processFrame();
|
||||
|
||||
// Bit 0 triggers wakeup. Bit 1 sleep state/ack sleep end. Bit 2 unk. Bit 15 IRQ enable (triggers IRQ 89).
|
||||
//if(REG_LGY_SLEEP & 2u) REG_HID_PADCNT = REG_LGY_PADCNT;
|
||||
}
|
||||
|
||||
Result LGY_backupGbaSave(void)
|
||||
{
|
||||
return PXI_sendCmd(IPC_CMD9_BACKUP_GBA_SAVE, NULL, 0);
|
||||
}
|
||||
|
||||
void LGY_deinit(void)
|
||||
{
|
||||
//REG_LGY_PAD_VAL = 0x1FFF; // Force all buttons not pressed.
|
||||
//REG_LGY_PAD_SEL = 0x1FFF;
|
||||
|
||||
LGY_backupGbaSave();
|
||||
LGYFB_deinit();
|
||||
|
||||
IRQ_unregisterIsr(IRQ_LGY_SLEEP);
|
||||
IRQ_unregisterIsr(IRQ_HID_PADCNT);
|
||||
}
|
|
@ -1,550 +0,0 @@
|
|||
#include <math.h>
|
||||
#include <stdatomic.h>
|
||||
#include "types.h"
|
||||
#include "arm11/hardware/lgyfb.h"
|
||||
#include "arm11/hardware/interrupt.h"
|
||||
#include "hardware/corelink_dma-330.h"
|
||||
#include "arm11/hardware/lcd.h"
|
||||
#include "hardware/gfx.h"
|
||||
#include "lgyfb_dma330.h"
|
||||
|
||||
|
||||
#define LGYFB_TOP_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x11000)
|
||||
#define REG_LGYFB_TOP_CNT *((vu32*)(LGYFB_TOP_REGS_BASE + 0x000))
|
||||
#define REG_LGYFB_TOP_SIZE *((vu32*)(LGYFB_TOP_REGS_BASE + 0x004))
|
||||
#define REG_LGYFB_TOP_STAT *((vu32*)(LGYFB_TOP_REGS_BASE + 0x008))
|
||||
#define REG_LGYFB_TOP_IRQ *((vu32*)(LGYFB_TOP_REGS_BASE + 0x00C))
|
||||
#define REG_LGYFB_TOP_FLUSH *((vu32*)(LGYFB_TOP_REGS_BASE + 0x010)) // Write 0 to flush LgyFb FIFO.
|
||||
#define REG_LGYFB_TOP_ALPHA *((vu32*)(LGYFB_TOP_REGS_BASE + 0x020))
|
||||
#define REG_LGYFB_TOP_UNK_F0 *((vu32*)(LGYFB_TOP_REGS_BASE + 0x0F0))
|
||||
#define REG_LGYFB_TOP_DITHPATT0 ((vu32*)(LGYFB_TOP_REGS_BASE + 0x100)) // 2 u32 regs with 4x2 pattern bits (mask 0xCCCC) each.
|
||||
#define REG_LGYFB_TOP_DITHPATT1 ((vu32*)(LGYFB_TOP_REGS_BASE + 0x108)) // 2 u32 regs with 4x2 pattern bits (mask 0xCCCC) each.
|
||||
|
||||
#define REG_LGYFB_TOP_V_LEN *((vu32*)(LGYFB_TOP_REGS_BASE + 0x200))
|
||||
#define REG_LGYFB_TOP_V_PATT *((vu32*)(LGYFB_TOP_REGS_BASE + 0x204))
|
||||
#define REG_LGYFB_TOP_V_ARRAY0 ((vu32*)(LGYFB_TOP_REGS_BASE + 0x240)) // 8 regs.
|
||||
#define REG_LGYFB_TOP_V_ARRAY1 ((vu32*)(LGYFB_TOP_REGS_BASE + 0x260)) // 8 regs.
|
||||
#define REG_LGYFB_TOP_V_ARRAY2 ((vu32*)(LGYFB_TOP_REGS_BASE + 0x280)) // 8 regs.
|
||||
#define REG_LGYFB_TOP_V_ARRAY3 ((vu32*)(LGYFB_TOP_REGS_BASE + 0x2A0)) // 8 regs.
|
||||
#define REG_LGYFB_TOP_V_ARRAY4 ((vu32*)(LGYFB_TOP_REGS_BASE + 0x2C0)) // 8 regs.
|
||||
#define REG_LGYFB_TOP_V_ARRAY5 ((vu32*)(LGYFB_TOP_REGS_BASE + 0x2E0)) // 8 regs.
|
||||
#define REG_LGYFB_TOP_V_MATRIX ((vu32 (*)[8])(LGYFB_TOP_REGS_BASE + 0x240)) // 6 * 8 regs.
|
||||
#define REG_LGYFB_TOP_H_LEN *((vu32*)(LGYFB_TOP_REGS_BASE + 0x300))
|
||||
#define REG_LGYFB_TOP_H_PATT *((vu32*)(LGYFB_TOP_REGS_BASE + 0x304))
|
||||
#define REG_LGYFB_TOP_H_ARRAY0 ((vu32*)(LGYFB_TOP_REGS_BASE + 0x340)) // 8 regs.
|
||||
#define REG_LGYFB_TOP_H_ARRAY1 ((vu32*)(LGYFB_TOP_REGS_BASE + 0x360)) // 8 regs.
|
||||
#define REG_LGYFB_TOP_H_ARRAY2 ((vu32*)(LGYFB_TOP_REGS_BASE + 0x380)) // 8 regs.
|
||||
#define REG_LGYFB_TOP_H_ARRAY3 ((vu32*)(LGYFB_TOP_REGS_BASE + 0x3A0)) // 8 regs.
|
||||
#define REG_LGYFB_TOP_H_ARRAY4 ((vu32*)(LGYFB_TOP_REGS_BASE + 0x3C0)) // 8 regs.
|
||||
#define REG_LGYFB_TOP_H_ARRAY5 ((vu32*)(LGYFB_TOP_REGS_BASE + 0x3E0)) // 8 regs.
|
||||
#define REG_LGYFB_TOP_H_MATRIX ((vu32 (*)[8])(LGYFB_TOP_REGS_BASE + 0x340)) // 6 * 8 regs.
|
||||
|
||||
#define LGYFB_TOP_FIFO *((const vu32*)(0x10311000))
|
||||
|
||||
|
||||
#define LGYFB_BOT_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x10000)
|
||||
#define REG_LGYFB_BOT_CNT *((vu32*)(LGYFB_BOT_REGS_BASE + 0x000))
|
||||
#define REG_LGYFB_BOT_SIZE *((vu32*)(LGYFB_BOT_REGS_BASE + 0x004))
|
||||
#define REG_LGYFB_BOT_STAT *((vu32*)(LGYFB_BOT_REGS_BASE + 0x008))
|
||||
#define REG_LGYFB_BOT_IRQ *((vu32*)(LGYFB_BOT_REGS_BASE + 0x00C))
|
||||
#define REG_LGYFB_BOT_FLUSH *((vu32*)(LGYFB_BOT_REGS_BASE + 0x010)) // Write 0 to flush LgyFb FIFO.
|
||||
#define REG_LGYFB_BOT_ALPHA *((vu32*)(LGYFB_BOT_REGS_BASE + 0x020)) // 8 bit alpha for all pixels.
|
||||
#define REG_LGYFB_BOT_UNK_F0 *((vu32*)(LGYFB_BOT_REGS_BASE + 0x0F0))
|
||||
#define REG_LGYFB_BOT_DITHPATT0 ((vu32*)(LGYFB_BOT_REGS_BASE + 0x100)) // 2 u32 regs with 4x2 pattern bits (mask 0xCCCC) each.
|
||||
#define REG_LGYFB_BOT_DITHPATT1 ((vu32*)(LGYFB_BOT_REGS_BASE + 0x108)) // 2 u32 regs with 4x2 pattern bits (mask 0xCCCC) each.
|
||||
|
||||
#define REG_LGYFB_BOT_V_LEN *((vu32*)(LGYFB_BOT_REGS_BASE + 0x200))
|
||||
#define REG_LGYFB_BOT_V_PATT *((vu32*)(LGYFB_BOT_REGS_BASE + 0x204))
|
||||
#define REG_LGYFB_BOT_V_ARRAY0 ((vu32*)(LGYFB_BOT_REGS_BASE + 0x240)) // 8 regs.
|
||||
#define REG_LGYFB_BOT_V_ARRAY1 ((vu32*)(LGYFB_BOT_REGS_BASE + 0x260)) // 8 regs.
|
||||
#define REG_LGYFB_BOT_V_ARRAY2 ((vu32*)(LGYFB_BOT_REGS_BASE + 0x280)) // 8 regs.
|
||||
#define REG_LGYFB_BOT_V_ARRAY3 ((vu32*)(LGYFB_BOT_REGS_BASE + 0x2A0)) // 8 regs.
|
||||
#define REG_LGYFB_BOT_V_ARRAY4 ((vu32*)(LGYFB_BOT_REGS_BASE + 0x2C0)) // 8 regs.
|
||||
#define REG_LGYFB_BOT_V_ARRAY5 ((vu32*)(LGYFB_BOT_REGS_BASE + 0x2E0)) // 8 regs.
|
||||
#define REG_LGYFB_BOT_V_MATRIX ((vu32 (*)[8])(LGYFB_BOT_REGS_BASE + 0x240)) // 6 * 8 regs.
|
||||
#define REG_LGYFB_BOT_H_LEN *((vu32*)(LGYFB_BOT_REGS_BASE + 0x300))
|
||||
#define REG_LGYFB_BOT_H_PATT *((vu32*)(LGYFB_BOT_REGS_BASE + 0x304))
|
||||
#define REG_LGYFB_BOT_H_ARRAY0 ((vu32*)(LGYFB_BOT_REGS_BASE + 0x340)) // 8 regs.
|
||||
#define REG_LGYFB_BOT_H_ARRAY1 ((vu32*)(LGYFB_BOT_REGS_BASE + 0x360)) // 8 regs.
|
||||
#define REG_LGYFB_BOT_H_ARRAY2 ((vu32*)(LGYFB_BOT_REGS_BASE + 0x380)) // 8 regs.
|
||||
#define REG_LGYFB_BOT_H_ARRAY3 ((vu32*)(LGYFB_BOT_REGS_BASE + 0x3A0)) // 8 regs.
|
||||
#define REG_LGYFB_BOT_H_ARRAY4 ((vu32*)(LGYFB_BOT_REGS_BASE + 0x3C0)) // 8 regs.
|
||||
#define REG_LGYFB_BOT_H_ARRAY5 ((vu32*)(LGYFB_BOT_REGS_BASE + 0x3E0)) // 8 regs.
|
||||
#define REG_LGYFB_BOT_H_MATRIX ((vu32 (*)[8])(LGYFB_BOT_REGS_BASE + 0x340)) // 6 * 8 regs.
|
||||
|
||||
#define LGYFB_BOT_FIFO *((const vu32*)(0x10310000))
|
||||
|
||||
|
||||
static bool g_frameReady = false;
|
||||
|
||||
|
||||
|
||||
static void lgyFbDmaIrqHandler(UNUSED u32 intSource)
|
||||
{
|
||||
DMA330_ackIrq(0);
|
||||
DMA330_run(0, program);
|
||||
|
||||
// We can't match the GBA refreshrate exactly so keep the LCDs around 90%
|
||||
// ahead of the GBA output which gives us a time window of around 1.6 ms to
|
||||
// render the frame and hopefully reduces output lag as much as possible.
|
||||
u32 vtotal;
|
||||
if(REG_LCD_PDC0_VPOS > 414 - 41) vtotal = 415; // Slower than GBA.
|
||||
else vtotal = 414; // Faster than GBA.
|
||||
REG_LCD_PDC0_VTOTAL = vtotal;
|
||||
|
||||
atomic_store_explicit(&g_frameReady, true, memory_order_relaxed);
|
||||
}
|
||||
|
||||
static void setScaleMatrixTop(u32 len, u32 patt, const s16 *const matrix)
|
||||
{
|
||||
REG_LGYFB_TOP_V_LEN = len - 1;
|
||||
REG_LGYFB_TOP_V_PATT = patt;
|
||||
REG_LGYFB_TOP_H_LEN = len - 1;
|
||||
REG_LGYFB_TOP_H_PATT = patt;
|
||||
|
||||
for(u32 y = 0; y < 6; y++)
|
||||
{
|
||||
for(u32 x = 0; x < len; x++)
|
||||
{
|
||||
const s16 tmp = matrix[len * y + x];
|
||||
|
||||
// Correct the color range using the scale matrix hardware.
|
||||
// For example when converting RGB555 to RGB8 LgyFb lazily shifts the 5 bits up
|
||||
// so 0b00011111 becomes 0b11111000. This creates wrong spacing between colors.
|
||||
// TODO: What is the "+ 8" good for?
|
||||
REG_LGYFB_TOP_V_MATRIX[y][x] = tmp * 0xFF / 0xF8 + 8;
|
||||
REG_LGYFB_TOP_H_MATRIX[y][x] = tmp + 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LGYFB_init(void)
|
||||
{
|
||||
if(DMA330_run(0, program)) return;
|
||||
|
||||
//REG_LGYFB_TOP_SIZE = LGYFB_SIZE(240u, 160u);
|
||||
REG_LGYFB_TOP_SIZE = LGYFB_SIZE(360u, 240u);
|
||||
REG_LGYFB_TOP_STAT = LGYFB_IRQ_MASK;
|
||||
REG_LGYFB_TOP_IRQ = 0;
|
||||
REG_LGYFB_TOP_ALPHA = 0xFF;
|
||||
|
||||
/*
|
||||
* Limitations:
|
||||
* First pattern bit must be 1 and last 0 (for V-scale) or it loses sync with the DS/GBA input.
|
||||
*
|
||||
* Matrix ranges:
|
||||
* in[-3] -1024-1023 (0xFC00-0x03FF)
|
||||
* in[-2] -4096-4095 (0xF000-0x0FFF)
|
||||
* in[-1] -32768-32767 (0x8000-0x7FFF)
|
||||
* in[0] -32768-32767 (0x8000-0x7FFF)
|
||||
* in[1] -4096-4095 (0xF000-0x0FFF)
|
||||
* in[2] -1024-1023 (0xFC00-0x03FF)
|
||||
*
|
||||
* Note: At scanline start the in FIFO is all filled with the first pixel.
|
||||
*/
|
||||
static const s16 scaleMatrix[6 * 6] =
|
||||
{
|
||||
// Original from AGB_FIRM.
|
||||
/* 0, 0, 0, 0, 0, 0, // in[-3]
|
||||
0, 0, 0, 0, 0, 0, // in[-2]
|
||||
0, 0x2000, 0x4000, 0, 0x2000, 0x4000, // in[-1]
|
||||
0x4000, 0x2000, 0, 0x4000, 0x2000, 0, // in[0]
|
||||
0, 0, 0, 0, 0, 0, // in[1]
|
||||
0, 0, 0, 0, 0, 0*/ // in[2]
|
||||
// out[0] out[1] out[2] out[3] out[4] out[5] out[6] out[7]
|
||||
|
||||
// Razor sharp (pixel duplication).
|
||||
/* 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0x4000, 0, 0, 0x4000,
|
||||
0x4000, 0x4000, 0, 0x4000, 0x4000, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0*/
|
||||
|
||||
// Sharp interpolated.
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0x2000, 0, 0, 0x2000,
|
||||
0x4000, 0x4000, 0x2000, 0x4000, 0x4000, 0x2000,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0
|
||||
};
|
||||
setScaleMatrixTop(6, 0b00011011, scaleMatrix);
|
||||
|
||||
// With RGB8 output solid red and blue are converted to 0xF8 and green to 0xFA.
|
||||
// The green bias exists on the whole range of green colors.
|
||||
// Some results:
|
||||
// RGBA8: Same as RGB8 but with useless alpha component.
|
||||
// RGB8: Observed best format. Invisible dithering and best color accuracy.
|
||||
// RGB565: A little visible dithering. Good color accuracy.
|
||||
// RGB5551: Lots of visible dithering. Good color accuracy (a little worse than 565).
|
||||
REG_LGYFB_TOP_CNT = LGYFB_DMA_E | LGYFB_OUT_SWIZZLE | LGYFB_OUT_FMT_8880 |
|
||||
LGYFB_HSCALE_E | LGYFB_VSCALE_E | LGYFB_ENABLE;
|
||||
|
||||
IRQ_registerIsr(IRQ_CDMA_EVENT0, 13, 0, lgyFbDmaIrqHandler);
|
||||
|
||||
|
||||
const double inGamma = 4.0;
|
||||
const double outGamma = 2.2;
|
||||
//const double contrast = .74851331406341291833644689906823; // GBA
|
||||
//const double brightness = .25148668593658708166355310093177; // GBA
|
||||
const double contrast = 1.0; // No-op
|
||||
const double brightness = 0.0; // No-op
|
||||
//REG_LCD_PDC0_GTBL_IDX = 0;
|
||||
for(u32 i = 0; i < 256; i++)
|
||||
{
|
||||
// Credits for this algo go to Extrems.
|
||||
// Originally from Game Boy Interface Standard Edition for the Game Cube.
|
||||
//const u32 x = (i & ~7u) | i>>5;
|
||||
u32 res = pow(pow(contrast, inGamma) * pow((double)i / 255.0f + brightness / contrast, inGamma),
|
||||
1.0 / outGamma) * 255.0f;
|
||||
if(res > 255) res = 255;
|
||||
|
||||
// Same adjustment for red/green/blue.
|
||||
REG_LCD_PDC0_GTBL_FIFO = res<<16 | res<<8 | res;
|
||||
}
|
||||
}
|
||||
|
||||
static void rotateFrame(void)
|
||||
{
|
||||
// 360x240, no filter.
|
||||
alignas(16) static const u8 firstList[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, 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 firstList[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
|
||||
};*/
|
||||
|
||||
// 360x240, no filter.
|
||||
alignas(16) static const u8 secondList[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 secondList[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
|
||||
};*/
|
||||
|
||||
static bool normalRender = false;
|
||||
u32 listSize;
|
||||
const u32 *list;
|
||||
if(normalRender == false)
|
||||
{
|
||||
normalRender = true;
|
||||
|
||||
listSize = 1136;
|
||||
list = (u32*)firstList;
|
||||
}
|
||||
else
|
||||
{
|
||||
listSize = 448;
|
||||
list = (u32*)secondList;
|
||||
}
|
||||
GX_processCommandList(listSize, list);
|
||||
GFX_waitForP3D();
|
||||
GX_displayTransfer((u32*)(0x18180000 + (16 * 240 * 3)), 368u<<16 | 240u,
|
||||
GFX_getFramebuffer(SCREEN_TOP) + (16 * 240 * 3), 368u<<16 | 240u, 1u<<12 | 1u<<8);
|
||||
GFX_waitForPPF();
|
||||
}
|
||||
|
||||
void LGYFB_processFrame(void)
|
||||
{
|
||||
if(atomic_load_explicit(&g_frameReady, memory_order_relaxed))
|
||||
{
|
||||
atomic_store_explicit(&g_frameReady, false, memory_order_relaxed);
|
||||
|
||||
// Rotate the frame using the GPU.
|
||||
// 240x160: TODO.
|
||||
// 360x240: about 0.623620315 ms.
|
||||
rotateFrame();
|
||||
GFX_swapFramebufs();
|
||||
}
|
||||
}
|
||||
|
||||
void LGYFB_deinit(void)
|
||||
{
|
||||
REG_LGYFB_TOP_CNT = 0;
|
||||
|
||||
DMA330_kill(0);
|
||||
|
||||
IRQ_unregisterIsr(IRQ_CDMA_EVENT0);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
#include "fsutil.h"
|
||||
void LGYFB_dbgDumpFrame(void)
|
||||
{
|
||||
/*GX_displayTransfer((u32*)0x18200000, 160u<<16 | 256u, (u32*)0x18400000, 160u<<16 | 256u, 1u<<12 | 1u<<8);
|
||||
GFX_waitForEvent(GFX_EVENT_PPF, false);
|
||||
fsQuickWrite((void*)0x18400000, "sdmc:/lgyfb_dbg_frame.bgr", 256 * 160 * 3);*/
|
||||
GX_displayTransfer((u32*)0x18200000, 240u<<16 | 512u, (u32*)0x18400000, 240u<<16 | 512u, 1u<<12 | 1u<<8);
|
||||
GFX_waitForEvent(GFX_EVENT_PPF, false);
|
||||
fsQuickWrite((void*)0x18400000, "sdmc:/lgyfb_dbg_frame.bgr", 512 * 240 * 3);
|
||||
}
|
||||
#endif
|
|
@ -1,45 +0,0 @@
|
|||
# 8 bytes burst with 15 transfers. Total 120 bytes per burst.
|
||||
# Source fixed address and destination incrementing.
|
||||
# Source and destination unprivileged, non-secure data access.
|
||||
MOV CCR, SB15 SS64 SAF SP2 DB15 DS64 DAI DP2
|
||||
MOV SAR, 0x10311000
|
||||
MOV DAR, 0x18200000
|
||||
|
||||
FLUSHP 14
|
||||
|
||||
|
||||
# Loop until the entire frame has been transferred.
|
||||
LPFE
|
||||
# Wait for single or burst requests.
|
||||
WFP 14, periph
|
||||
|
||||
# Transfer 8 scanlines.
|
||||
# For width 240:
|
||||
#LP 29 # RGB5551 & RGB565, 128 bytes burst
|
||||
#LP 44 # RGB8, 128 bytes burst
|
||||
#LP 59 # RGBA8, 128 bytes burst
|
||||
|
||||
# For width 360:
|
||||
#LP 44 # RGB5551 & RGB565, 128 bytes burst
|
||||
LP 71 # RGB8, 120 bytes burst
|
||||
#LP 89 # RGBA8, 128 bytes burst
|
||||
LDB
|
||||
STB
|
||||
LPENDB
|
||||
LDPB 14
|
||||
STB
|
||||
|
||||
# Skip gaps swizzle edition™.
|
||||
# For width 240:
|
||||
#ADDH DAR, 0x100 # RGB5551 & RGB565
|
||||
#ADDH DAR, 0x180 # RGB8
|
||||
#ADDH DAR, 0x200 # RGBA8
|
||||
|
||||
#For width 360:
|
||||
#ADDH DAR, 0x980 # RGB5551 & RGB565
|
||||
ADDH DAR, 0xE40 # RGB8
|
||||
#ADDH DAR, 0x1300 # RGBA8
|
||||
LPEND
|
||||
WMB
|
||||
SEV 0
|
||||
END
|
|
@ -1,110 +0,0 @@
|
|||
/*
|
||||
* 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 <stdatomic.h>
|
||||
#include "arm11/hardware/mcu.h"
|
||||
#include "arm11/hardware/i2c.h"
|
||||
#include "arm11/hardware/interrupt.h"
|
||||
#include "arm11/hardware/gpio.h"
|
||||
|
||||
|
||||
static bool g_mcuIrq = false;
|
||||
static u32 g_mcuEvents = 0;
|
||||
|
||||
|
||||
|
||||
static void mcuIrqHandler(UNUSED u32 intSource);
|
||||
|
||||
u8 MCU_readReg(McuReg reg)
|
||||
{
|
||||
return I2C_readReg(I2C_DEV_CTR_MCU, reg);
|
||||
}
|
||||
|
||||
bool MCU_writeReg(McuReg reg, u8 data)
|
||||
{
|
||||
return I2C_writeReg(I2C_DEV_CTR_MCU, reg, data);
|
||||
}
|
||||
|
||||
bool MCU_readRegBuf(McuReg reg, u8 *out, u32 size)
|
||||
{
|
||||
return I2C_readRegBuf(I2C_DEV_CTR_MCU, reg, out, size);
|
||||
}
|
||||
|
||||
bool MCU_writeRegBuf(McuReg reg, const u8 *const in, u32 size)
|
||||
{
|
||||
return I2C_writeRegBuf(I2C_DEV_CTR_MCU, reg, in, size);
|
||||
}
|
||||
|
||||
void MCU_init(void)
|
||||
{
|
||||
static bool inited = false;
|
||||
if(inited) return;
|
||||
inited = true;
|
||||
|
||||
I2C_init();
|
||||
|
||||
// Configure GPIO for MCU event IRQs
|
||||
GPIO_config(GPIO_3_MCU, GPIO_INPUT | GPIO_EDGE_FALLING | GPIO_IRQ_ENABLE);
|
||||
IRQ_registerIsr(IRQ_CTR_MCU, 14, 0, mcuIrqHandler);
|
||||
|
||||
atomic_store_explicit(&g_mcuIrq, true, memory_order_relaxed);
|
||||
(void)MCU_getEvents(0);
|
||||
|
||||
MCU_setEventMask(0xC0BF3F80);
|
||||
}
|
||||
|
||||
static void mcuIrqHandler(UNUSED u32 intSource)
|
||||
{
|
||||
g_mcuIrq = true;
|
||||
}
|
||||
|
||||
bool MCU_setEventMask(u32 mask)
|
||||
{
|
||||
return MCU_writeRegBuf(MCU_REG_EVENT_MASK, (const u8*)&mask, 4);
|
||||
}
|
||||
|
||||
u32 MCU_getEvents(u32 mask)
|
||||
{
|
||||
u32 events = g_mcuEvents;
|
||||
|
||||
if(atomic_load_explicit(&g_mcuIrq, memory_order_relaxed))
|
||||
{
|
||||
atomic_store_explicit(&g_mcuIrq, false, memory_order_relaxed);
|
||||
|
||||
u32 data;
|
||||
if(!MCU_readRegBuf(MCU_REG_EVENTS, (u8*)&data, 4)) return 0;
|
||||
|
||||
events |= data;
|
||||
}
|
||||
|
||||
g_mcuEvents = events & ~mask;
|
||||
|
||||
return events & mask;
|
||||
}
|
||||
|
||||
u32 MCU_waitEvents(u32 mask)
|
||||
{
|
||||
u32 events;
|
||||
|
||||
while((events = MCU_getEvents(mask)) == 0u)
|
||||
{
|
||||
__wfi();
|
||||
}
|
||||
|
||||
return events;
|
||||
}
|
|
@ -1,253 +0,0 @@
|
|||
/*
|
||||
* 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"
|
||||
#include "mem_map.h"
|
||||
#include "fb_assert.h"
|
||||
#include "arm11/hardware/scu.h"
|
||||
#include "mmio.h"
|
||||
#include "arm.h"
|
||||
|
||||
|
||||
// Mem permissions. Bit 5 (APX), 1-0 (AP[1:0]), all other padding.
|
||||
#define PERM_NA (0b000000u)
|
||||
#define PERM_PRIV_RW_USR_NA (0b000001u)
|
||||
#define PERM_PRIV_RW_USR_RO (0b000010u)
|
||||
#define PERM_PRIV_RW_USR_RW (0b000011u)
|
||||
// These 2 don't work for supersections because no APX bit.
|
||||
#define PERM_PRIV_RO_USR_NA (0b100001u)
|
||||
#define PERM_PRIV_RO_USR_RO (0b100010u)
|
||||
|
||||
// Predefined mem attributes. Bit 12-10 (TEX[2:0]), 1 (C), 0 (B), all other padding.
|
||||
// All of these count for outer and inner.
|
||||
#define ATTR_STRONGLY_ORDERED (0b0000000000000u) // Always shared
|
||||
#define ATTR_SHARED_DEVICE (0b0000000000001u)
|
||||
#define ATTR_NORM_WRITE_TROUGH_NO_ALLOC (0b0000000000010u) // Behaves as noncacheable on ARM11 MPCore.
|
||||
#define ATTR_NORM_WRITE_BACK_NO_ALLOC (0b0000000000011u) // Behaves as write-back write-allocate.
|
||||
#define ATTR_NORM_NONCACHABLE (0b0010000000000u)
|
||||
#define ATTR_NORM_WRITE_BACK_ALLOC (0b0010000000011u)
|
||||
#define ATTR_NONSHARED_DEVICE (0b0100000000000u)
|
||||
|
||||
// Policies for custom normal memory attributes.
|
||||
#define POLI_NONCACHABLE_UNBUFFERED (0b00u)
|
||||
#define POLI_WRITE_BACK_ALLOC_BUFFERED (0b01u)
|
||||
#define POLI_WRITE_THROUGH_NO_ALLOC_BUFFERED (0b10u) // Behaves as noncacheable on ARM11 MPCore.
|
||||
#define POLI_WRITE_BACK_NO_ALLOC_BUFFERED (0b11u) // Behaves as write-back write-allocate.
|
||||
|
||||
// Make custom normal memory attributes.
|
||||
#define CUSTOM_ATTR(outer, inner) (1u<<12 | (outer)<<10 | (inner))
|
||||
|
||||
// Converts the attribute bits from L1 format to L2 format.
|
||||
// Required for mmuMapPages().
|
||||
#define L1_TO_L2(attr) (((attr)>>6 | (attr)) & 0x73)
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 l1[4096];
|
||||
u32 l2PrivReg[256]; // L2 table for MPCore private region
|
||||
u32 l2Axiwram[256]; // L2 table for AXIWRAM
|
||||
u32 l2Boot11[256]; // L2 table for boot11 (high vectors)
|
||||
} MmuTables;
|
||||
static MmuTables *const mmuTables = (MmuTables*)A11_MMU_TABLES_BASE;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Maps up to 256 16 MiB sections of memory. Domain is always 0.
|
||||
*
|
||||
* @param[in] va The virtual address base. Must be aligned to 16 MiB.
|
||||
* @param[in] pa The physical address base. Must be aligned to 16 MiB.
|
||||
* @param[in] num The number of sections to map.
|
||||
* @param[in] access The access permission bits.
|
||||
* @param[in] xn If this memory should be marked as execute never.
|
||||
* @param[in] attr Other attribute bits like caching.
|
||||
*/
|
||||
static void mmuMapSupersections(u32 va, u32 pa, u32 num, u8 access, bool xn, u32 attr)
|
||||
{
|
||||
fb_assert(!(va & ~0xFF000000));
|
||||
fb_assert(!(pa & ~0xFF000000));
|
||||
fb_assert(num < 256);
|
||||
|
||||
u32 *const l1Table = mmuTables->l1;
|
||||
for(u32 i = 0; i < 0x1000000 * num; i += 0x1000000)
|
||||
{
|
||||
const u32 l1Ss = (va + i)>>20;
|
||||
for(u32 n = 0; n < 16; n++)
|
||||
{
|
||||
l1Table[l1Ss + n] = (pa + i) | 1u<<18 | access<<10 | xn<<4 | attr<<2 | 0b10u;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Maps up to 4096 1 MiB sections of memory.
|
||||
*
|
||||
* @param[in] va The virtual address base. Must be aligned to 1 MiB.
|
||||
* @param[in] pa The physical address base. Must be aligned to 1 MiB.
|
||||
* @param[in] num The number of sections to map.
|
||||
* @param[in] shared If the sections are shared memory.
|
||||
* @param[in] access The access permission bits.
|
||||
* @param[in] domain One of the 16 possible domains.
|
||||
* @param[in] xn If this memory should be marked as execute never.
|
||||
* @param[in] attr Other attribute bits like caching.
|
||||
*/
|
||||
static void mmuMapSections(u32 va, u32 pa, u32 num, bool shared, u8 access, u8 domain, bool xn, u32 attr)
|
||||
{
|
||||
fb_assert(!(va & ~0xFFF00000));
|
||||
fb_assert(!(pa & ~0xFFF00000));
|
||||
fb_assert(num < 4096);
|
||||
|
||||
u32 *const l1Table = mmuTables->l1;
|
||||
for(u32 i = 0; i < 0x100000 * num; i += 0x100000)
|
||||
{
|
||||
l1Table[(va + i)>>20] = (pa + i) | shared<<16 | access<<10 |
|
||||
domain<<5 | xn<<4 | attr<<2 | 0b10u;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Maps up to 256 4 KiB pages of memory.
|
||||
* @brief The mapped range must not cross the next section.
|
||||
*
|
||||
* @param[in] va The virtual address base. Must be aligned to 4 KiB.
|
||||
* @param[in] pa The physical address base. Must be aligned to 4 KiB.
|
||||
* @param[in] num The number of pages to map.
|
||||
* @param l2Table The L2 MMU table address base for this mapping.
|
||||
* @param[in] shared If the pages are shared memory.
|
||||
* @param[in] access The access permission bits.
|
||||
* @param[in] domain One of the 16 possible domains.
|
||||
* @param[in] xn If this memory should be marked as execute never.
|
||||
* @param[in] attr Other attribute bits like caching.
|
||||
*/
|
||||
static void mmuMapPages(u32 va, u32 pa, u32 num, u32 *const l2Table, bool shared, u8 access, u8 domain, bool xn, u32 attr)
|
||||
{
|
||||
fb_assert(!(va & ~0xFFFFF000));
|
||||
fb_assert(!(pa & ~0xFFFFF000));
|
||||
fb_assert(num < 256);
|
||||
fb_assert(!((u32)l2Table & ~0xFFFFFC00));
|
||||
|
||||
for(u32 i = 0; i < 0x1000 * num; i += 0x1000)
|
||||
{
|
||||
l2Table[(va + i)>>12 & 0xFF] = ((pa + i) & 0xFFFFF000) | shared<<10 | access<<4 | attr<<2 | 0b10u | xn;
|
||||
}
|
||||
|
||||
mmuTables->l1[va>>20] = (u32)l2Table | domain<<5 | 0b01u;
|
||||
}
|
||||
|
||||
void setupMmu(void)
|
||||
{
|
||||
// FCSE PID Register (FCSE PID = 0)
|
||||
// Note: This must be 0 before disabling the MMU otherwise UB
|
||||
__setFcsepidr(0);
|
||||
// Context ID Register (ASID = 0, PROCID = 0)
|
||||
__setCidr(0);
|
||||
// TTBR0 address shared page table walk and outer cachable write-through, no allocate on write
|
||||
__setTtbr0((u32)mmuTables->l1 | 0x12);
|
||||
// Use the 16 KiB L1 table only
|
||||
__setTtbcr(0);
|
||||
// Domain 0 = client, remaining domains all = no access
|
||||
__setDacr(1);
|
||||
|
||||
|
||||
static volatile bool syncFlag = false;
|
||||
if(!__getCpuId())
|
||||
{
|
||||
// Clear L1 and L2 tables
|
||||
iomemset((u32*)mmuTables, 0, sizeof(MmuTables));
|
||||
|
||||
// IO mem mapping
|
||||
mmuMapSections(IO_MEM_ARM9_ARM11, IO_MEM_ARM9_ARM11, 4, true,
|
||||
PERM_PRIV_RW_USR_NA, 0, true, ATTR_SHARED_DEVICE);
|
||||
|
||||
// MPCore private region mapping
|
||||
mmuMapPages(MPCORE_PRIV_REG_BASE, MPCORE_PRIV_REG_BASE, 2,
|
||||
mmuTables->l2PrivReg, false, PERM_PRIV_RW_USR_NA,
|
||||
0, true, L1_TO_L2(ATTR_SHARED_DEVICE));
|
||||
|
||||
// VRAM mapping
|
||||
mmuMapSections(VRAM_BASE, VRAM_BASE, 6, true, PERM_PRIV_RW_USR_NA, 0,
|
||||
true, ATTR_NORM_WRITE_TROUGH_NO_ALLOC);
|
||||
|
||||
// AXIWRAM core 0/1 stack mapping
|
||||
mmuMapPages(A11_C0_STACK_START, A11_C0_STACK_START, 4, mmuTables->l2Axiwram,
|
||||
true, PERM_PRIV_RW_USR_NA, 0, true, L1_TO_L2(ATTR_NORM_WRITE_BACK_ALLOC));
|
||||
|
||||
// AXIWRAM MMU table mapping
|
||||
const u32 mmuTablesPages = ((sizeof(MmuTables) + 0xFFFu) & ~0xFFFu) / 0x1000;
|
||||
mmuMapPages((u32)mmuTables, (u32)mmuTables, mmuTablesPages, mmuTables->l2Axiwram, true,
|
||||
PERM_PRIV_RO_USR_NA, 0, true, L1_TO_L2(ATTR_NORM_WRITE_TROUGH_NO_ALLOC));
|
||||
|
||||
extern const u32 __start__[];
|
||||
extern const u32 __text_pages__[];
|
||||
extern const u32 __rodata_start__[];
|
||||
extern const u32 __rodata_pages__[];
|
||||
extern const u32 __data_start__[];
|
||||
const u32 dataPages = (AXIWRAM_BASE + AXIWRAM_SIZE - (u32)__data_start__) / 0x1000;
|
||||
|
||||
// text
|
||||
mmuMapPages((u32)__start__, (u32)__start__, (u32)__text_pages__,
|
||||
mmuTables->l2Axiwram, true, PERM_PRIV_RO_USR_NA, 0, false,
|
||||
L1_TO_L2(ATTR_NORM_WRITE_BACK_ALLOC));
|
||||
// rodata
|
||||
mmuMapPages((u32)__rodata_start__, (u32)__rodata_start__, (u32)__rodata_pages__,
|
||||
mmuTables->l2Axiwram, true, PERM_PRIV_RO_USR_NA, 0, true,
|
||||
L1_TO_L2(ATTR_NORM_WRITE_BACK_ALLOC));
|
||||
// data, bss and heap
|
||||
mmuMapPages((u32)__data_start__, (u32)__data_start__, dataPages,
|
||||
mmuTables->l2Axiwram, true, PERM_PRIV_RW_USR_NA, 0, true,
|
||||
L1_TO_L2(ATTR_NORM_WRITE_BACK_ALLOC));
|
||||
|
||||
// FCRAM with New 3DS extension
|
||||
mmuMapSupersections(FCRAM_BASE, FCRAM_BASE, 16, PERM_PRIV_RW_USR_NA, true,
|
||||
ATTR_NORM_WRITE_BACK_ALLOC);
|
||||
|
||||
// Map fastboot executable start to boot11 mirror (exception vectors)
|
||||
mmuMapPages(BOOT11_MIRROR2, (u32)__start__, 1, mmuTables->l2Boot11, true,
|
||||
PERM_PRIV_RO_USR_NA, 0, false, L1_TO_L2(ATTR_NORM_WRITE_BACK_ALLOC));
|
||||
|
||||
// Invalidate tag RAMs before enabling SMP as recommended by the MPCore doc.
|
||||
REG_SCU_CNT = 0x1FFE; // Disable SCU and parity checking. Access to all CPUs interfaces.
|
||||
REG_SCU_INVAL_TAG = 0xFFFF; // Invalidate SCU tag RAMs of all CPUs.
|
||||
REG_SCU_CNT = 0x1FFEu | 1; // Enable SCU.
|
||||
|
||||
syncFlag = true;
|
||||
__sev();
|
||||
}
|
||||
else while(!syncFlag) __wfe();
|
||||
|
||||
|
||||
// Invalidate TLB (Unified TLB operation)
|
||||
__asm__ volatile("mcr p15, 0, %0, c8, c7, 0" : : "r" (0) : "memory");
|
||||
__dsb();
|
||||
|
||||
|
||||
// Enable Return stack, Dynamic branch prediction, Static branch prediction,
|
||||
// Instruction folding and SMP mode: the CPU is taking part in coherency
|
||||
__setAcr(__getAcr() | 0x2F);
|
||||
|
||||
// Enable MMU, D-Cache, Program flow prediction,
|
||||
// I-Cache, high exception vectors, Unaligned data access,
|
||||
// subpage AP bits disabled
|
||||
__setCr(__getCr() | 0xC03805);
|
||||
|
||||
// Invalidate Both Caches. Also flushes the branch target cache
|
||||
__asm__ volatile("mcr p15, 0, %0, c7, c7, 0" : : "r" (0) : "memory");
|
||||
__dsb();
|
||||
__isb();
|
||||
}
|
|
@ -1,170 +0,0 @@
|
|||
/*
|
||||
* 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 "arm11/hardware/pdn.h"
|
||||
#include "arm11/hardware/cfg11.h"
|
||||
#include "arm.h"
|
||||
#include "arm11/hardware/interrupt.h"
|
||||
#include "arm11/start.h"
|
||||
#include "util.h"
|
||||
#include "arm11/hardware/scu.h"
|
||||
|
||||
|
||||
|
||||
#ifdef CORE123_INIT
|
||||
static void NAKED core23Entry(void)
|
||||
{
|
||||
__cpsid(aif);
|
||||
REG_GIC_CPU_CTRL = 1;
|
||||
|
||||
const u32 cpuId = __getCpuId();
|
||||
// Tell core 0 we are here
|
||||
if(cpuId == 3) REGs_PDN_MPCORE_BOOTCNT[3] = MPCORE_BOOTCNT_RST;
|
||||
else REGs_PDN_MPCORE_BOOTCNT[2] = MPCORE_BOOTCNT_RST;
|
||||
|
||||
// Wait for IPI 2 (core 2) or IPI 3 (core 3)
|
||||
u32 tmp;
|
||||
do
|
||||
{
|
||||
__wfi();
|
||||
tmp = REG_GIC_CPU_INTACK;
|
||||
REG_GIC_CPU_EOI = tmp;
|
||||
} while(tmp != cpuId);
|
||||
|
||||
// Jump to real entrypoint
|
||||
_start();
|
||||
}
|
||||
#endif
|
||||
|
||||
void PDN_core123Init(void)
|
||||
{
|
||||
if(REG_CFG11_SOCINFO & SOCINFO_N3DS_PROTO)
|
||||
{
|
||||
REG_GIC_CPU_CTRL = 1;
|
||||
for(u32 i = 0; i < 4; i++) REGs_GIC_DIST_ENABLE_CLEAR[i] = 0xFFFFFFFFu;
|
||||
REGs_GIC_DIST_PENDING_CLEAR[2] = 0x1000000; // Interrupt ID 88
|
||||
REGs_GIC_DIST_PRI[22] = 0;
|
||||
REGs_GIC_DIST_TARGET[22] = 1;
|
||||
REGs_GIC_DIST_ENABLE_SET[2] = 0x1000000;
|
||||
|
||||
#ifdef CORE123_INIT
|
||||
u16 socmode;
|
||||
// If non-prototype SoC use 804 MHz.
|
||||
if(REG_CFG11_SOCINFO & SOCINFO_N3DS) socmode = SOCMODE_N3DS_804MHz;
|
||||
else socmode = SOCMODE_N3DS_PROTO_536MHz;
|
||||
|
||||
if((REG_PDN_MPCORE_SOCMODE & SOCMODE_MASK) != socmode)
|
||||
{
|
||||
// No idea what this does
|
||||
if(REG_CFG11_SOCINFO & SOCINFO_N3DS) REG_PDN_MPCORE_CNT = PDN_MPCORE_CNT_L2C_E | PDN_MPCORE_CNT_MEM_EXT_E;
|
||||
else REG_PDN_MPCORE_CNT = PDN_MPCORE_CNT_MEM_EXT_E;
|
||||
|
||||
// Necessary delay.
|
||||
wait(403);
|
||||
|
||||
PDN_setSocmode(socmode);
|
||||
REGs_GIC_DIST_PENDING_CLEAR[2] = 0x1000000;
|
||||
REG_CFG11_GPU_N3DS_CNT = GPU_N3DS_CNT_TEX_FIX | GPU_N3DS_CNT_N3DS_MODE;
|
||||
}
|
||||
REG_CFG11_CDMA_PERIPHERALS = CDMA_PERIPHERALS_ALL; // Redirect all to CDMA2.
|
||||
|
||||
if((REG_SCU_CONFIG & 3) == 3)
|
||||
{
|
||||
// Set core 2/3 to normal mode (running)
|
||||
REG_SCU_CPU_STAT &= ~0b11110000;
|
||||
|
||||
const u16 socmode = REG_PDN_MPCORE_SOCMODE & SOCMODE_MASK;
|
||||
u16 tmpSocmode;
|
||||
if(REG_CFG11_SOCINFO & SOCINFO_N3DS) tmpSocmode = SOCMODE_N3DS_268MHz;
|
||||
else tmpSocmode = SOCMODE_N3DS_PROTO_268MHz;
|
||||
|
||||
if(socmode != tmpSocmode)
|
||||
{
|
||||
PDN_setSocmode(tmpSocmode);
|
||||
REGs_GIC_DIST_PENDING_CLEAR[2] = 0x1000000;
|
||||
}
|
||||
|
||||
REG_CFG11_BOOTROM_OVERLAY_CNT = BOOTROM_OVERLAY_CNT_E;
|
||||
REG_CFG11_BOOTROM_OVERLAY_VAL = (u32)core23Entry;
|
||||
// If not already done enable instruction and data overlays
|
||||
if(!(REGs_PDN_MPCORE_BOOTCNT[2] & MPCORE_BOOTCNT_RST_STAT))
|
||||
{
|
||||
REGs_PDN_MPCORE_BOOTCNT[2] = MPCORE_BOOTCNT_D_OVERL_E | MPCORE_BOOTCNT_RST;
|
||||
}
|
||||
if(!(REGs_PDN_MPCORE_BOOTCNT[3] & MPCORE_BOOTCNT_RST_STAT))
|
||||
{
|
||||
REGs_PDN_MPCORE_BOOTCNT[3] = MPCORE_BOOTCNT_D_OVERL_E | MPCORE_BOOTCNT_RST;
|
||||
}
|
||||
// Wait for core 2/3 to jump out of boot11
|
||||
while((REGs_PDN_MPCORE_BOOTCNT[2] & (MPCORE_BOOTCNT_RST_STAT | MPCORE_BOOTCNT_D_OVERL_E))
|
||||
!= MPCORE_BOOTCNT_RST_STAT);
|
||||
while((REGs_PDN_MPCORE_BOOTCNT[3] & (MPCORE_BOOTCNT_RST_STAT | MPCORE_BOOTCNT_D_OVERL_E))
|
||||
!= MPCORE_BOOTCNT_RST_STAT);
|
||||
REG_CFG11_BOOTROM_OVERLAY_CNT = 0; // Disable all overlays
|
||||
|
||||
// Set clock back to original one
|
||||
if(socmode != tmpSocmode) PDN_setSocmode(socmode);
|
||||
}
|
||||
|
||||
REGs_GIC_DIST_ENABLE_CLEAR[2] = 0x1000000;
|
||||
|
||||
// Wakeup core 2/3 and let them jump to their entrypoint.
|
||||
IRQ_softwareInterrupt(2, 0b0100);
|
||||
IRQ_softwareInterrupt(3, 0b1000);
|
||||
#else
|
||||
// Just enables the New3DS FCRAM extension (if not already done).
|
||||
if((REG_PDN_MPCORE_SOCMODE & SOCMODE_MASK) != SOCMODE_N3DS_268MHz)
|
||||
PDN_setSocmode(SOCMODE_N3DS_268MHz);
|
||||
|
||||
REGs_GIC_DIST_ENABLE_CLEAR[2] = 0x1000000;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Wakeup core 1
|
||||
*((vu32*)0x1FFFFFDC) = (u32)_start; // Core 1 entrypoint
|
||||
IRQ_softwareInterrupt(1, 0b0010);
|
||||
}
|
||||
|
||||
void PDN_setSocmode(PdnSocmode socmode)
|
||||
{
|
||||
REG_PDN_MPCORE_SOCMODE = PDN_MPCORE_SOCMODE_ACK | socmode;
|
||||
do
|
||||
{
|
||||
__wfi();
|
||||
} while(!(REG_PDN_MPCORE_SOCMODE & PDN_MPCORE_SOCMODE_ACK));
|
||||
}
|
||||
|
||||
void PDN_poweroffCore23(void)
|
||||
{
|
||||
if(REG_CFG11_SOCINFO & SOCINFO_N3DS_PROTO)
|
||||
{
|
||||
REGs_PDN_MPCORE_BOOTCNT[2] = 0;
|
||||
REGs_PDN_MPCORE_BOOTCNT[3] = 0;
|
||||
|
||||
REG_CFG11_CDMA_PERIPHERALS = 0;
|
||||
REG_CFG11_GPU_N3DS_CNT = 0;
|
||||
|
||||
REG_PDN_MPCORE_CNT = 0;
|
||||
PDN_setSocmode(SOCMODE_N3DS_268MHz);
|
||||
|
||||
REG_SCU_CPU_STAT |= 0b1111<<4;
|
||||
|
||||
PDN_setSocmode(SOCMODE_O3DS_268MHz);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue