Compare commits

..

173 Commits

Author SHA1 Message Date
profi200 6b882e9395
Don't run actions on pull requests. 2024-12-06 22:37:25 +01:00
profi200 4e4c2aa2b5
Updated all libretro based color profiles.
Added GB micro, GBA SP (AGS-101), DS lite and VBA/No$GBA profiles.
2024-12-04 00:44:14 +01:00
profi200 dd90d498c4
!Breaking change! Changed the config file format to use strings in many places instead of values.
Added a new saturation setting for color profiles other than none.
Removed lcdGamma and displayGamma temporarily.
Updated README.md with all the changes.
2024-12-03 20:34:53 +01:00
Elouan Martinet 877f7c61d0 Add an option to use current rom directory for config and saves 2024-10-28 09:30:36 +01:00
profi200 7a7190baea
[README] Mention that oaf is not affected by the screen wrap bug because people are talking shit. 2024-09-22 15:14:03 +02:00
profi200 edd43a6fcc
Updated libn3ds.
Fixed hang on power off when all backlights are off (libn3ds).
Screenshots are now always in native resolution.
2024-08-30 18:45:24 +02:00
profi200 50e2f30e0d
[README] Mention new features and oaf is no longer in alpha. 2024-08-02 19:35:52 +02:00
profi200 79b2457e8b
[File browser] Filter out all entries starting with a dot. F.....g Mac OS. 2024-07-31 16:19:46 +02:00
profi200 5356e5c89a
Implemented full gamma correction for top LCDs which improves colors noticeably without crushing details in shadows.
The disadvantage is that the gbaGamma, lcdGamma, brightness and contrast settings don't work anymore for now. They will be reimplemented with color profile settings later.
2024-07-30 16:37:05 +02:00
profi200 67ce019b36
Forgot to check the ROM size before adding the padding. 2024-07-26 21:22:40 +02:00
profi200 41db8760a6
Made ROM padding code ~42% faster. 2024-07-26 20:37:49 +02:00
profi200 3a70cdc27f Improved README for screenshots and color correction. 2024-07-25 17:19:41 +02:00
profi200 b1c66e24a2 Added experimental support for true color correction to mimic the look of the crappy GBA LCD. Thanks to hunterk and Pokefan531 for their work on the libretro shaders this is based on. 2024-07-25 17:19:41 +02:00
profi200 f7efd62ea9 Fixed save type selector cursor at the wrong position and added cache flushing. 2024-07-25 17:19:41 +02:00
profi200 073daac2bb Separated video functions into own .c file. 2024-07-25 17:19:41 +02:00
profi200 15436e02a7 Updated submodules.
Fixed compatibility with latest libn3ds.
2024-07-25 17:19:41 +02:00
profi200 3e91716c80 c2x --> c23. Supported since gcc 14.1.0. 2024-07-25 17:19:41 +02:00
profi200 f9786b14a1 Updated libn3ds for a critical GPIO fix. Also updated the other submodules. 2024-07-25 17:19:41 +02:00
profi200 bd5b207106 Updated bitmap.h with comments. 2024-07-25 17:19:41 +02:00
profi200 7c8c3d6fe8 Load GBA scaler matrix from SD if found. 2024-07-25 17:19:41 +02:00
profi200 6cf6059023 Updated libn3ds submodule for the capture card workaround. 2024-07-25 17:19:41 +02:00
profi200 1ad621d4f4 Fixed a file handle leak just introduced by myself. Thanks @PSI-Rockin for finding it. 2024-07-25 17:19:41 +02:00
profi200 9f331c24f7 Use a more safe variant of binary search for the GBA db. 2024-07-25 17:19:41 +02:00
profi200 3ffb706f3b Fixed strict-aliasing warning in save_type.c. 2024-07-25 17:19:41 +02:00
profi200 c85a4b1b57 Fixed strict-aliasing warnings in gpu_cmd_lists.c. 2024-07-25 17:19:41 +02:00
profi200 6db20e190c Added min macro to patch.c because it was removed from libn3ds. 2024-07-25 17:19:41 +02:00
profi200 d7f701f02a Fixed compatibility with latest libn3ds. 2024-07-25 17:19:41 +02:00
profi200 2bca9b04b6 Updated submodules. 2024-07-25 17:19:41 +02:00
profi200 678cbd9ae3
Automatic builds from all branches. 2024-05-19 22:36:52 +02:00
profi200 479069d039
Updated README.md adding the missing [input] to the example. 2024-04-08 15:36:49 +02:00
profi200 99cf0fdacc
Updated to checkout/cache/upload-artifact v4. 2024-02-24 20:58:04 +01:00
Nemris 9d13ad3722 Refactor IPS patching. 2024-02-24 20:45:18 +01:00
Nemris 07bdaf521d Normalize indentation. 2024-02-24 20:45:18 +01:00
profi200 e14704181c
Round the gamma table entries instead of discarding the fraction part. 2024-01-29 17:43:58 +01:00
profi200 63e4422db1
Cleaned up the old gamma table adjustment code a little. 2023-10-06 16:11:20 +02:00
profi200 b554c7c35c
Updated libn3ds and some defines. 2023-10-06 16:10:29 +02:00
profi200 5f46a967a8
Hardcode GPU cmd list sizes in the header instead of 2 places so i don't make *that* mistake again. 2023-09-20 00:24:47 +02:00
profi200 dc5ac1749f
Fixed ROM mirrors for 1 MiB ROMs. Thanks to @endrift for discovering this. 2023-09-20 00:15:31 +02:00
profi200 855f6b131a
Added a few missing copyright headers. 2023-09-19 20:58:03 +02:00
profi200 e77b04f089
Split open_agb_firm.c into more .c files. A long overdue change. 2023-09-19 20:48:07 +02:00
profi200 ddba28b226
Fixed a double free oopsie. 2023-08-25 13:17:56 +02:00
profi200 8db77d523e
Oops, this happens when not checking wtf the written code actually does. 2023-08-23 02:33:22 +02:00
profi200 4377d28d14
Use macro for GPU render buffer address. 2023-08-23 02:26:09 +02:00
profi200 1ca27c22f6
Disable borders for scaled modes. There are so few pixels left they don't make sense. 2023-08-23 02:21:50 +02:00
profi200 6766b224dc
Set scale matrix outside libn3ds. 2023-08-23 02:09:29 +02:00
profi200 a3c8f76e82
Use glob matching in .gitignore. 2023-08-23 02:04:39 +02:00
Harrison 92c591da22
GBA database updates (#128) 2023-08-23 01:30:01 +02:00
profi200 0f55ad941c
Updated libn3ds. 2023-08-12 18:18:06 +02:00
profi200 cf7d1915e0
Added software audio volume control. 2023-08-12 18:17:13 +02:00
profi200 8ecc7ce458
Added border support for 1:1 scaling mode. 2023-08-10 22:29:16 +02:00
profi200 4f96bae9d3
Updated libraries/submodules. 2023-08-07 01:57:45 +02:00
profi200 014c341e67
Added button remapping. Closes #25. 2023-08-07 01:57:15 +02:00
profi200 726a4f3355
Implemented proper headphone detection.
Added a config option to override the audio output.
2023-08-05 02:07:13 +02:00
profi200 30351188a4
Updated libs/submodules. 2023-08-05 02:06:15 +02:00
profi200 cecd0d31f3
Cache ctr_firm_builder. 2023-05-02 03:43:04 +02:00
profi200 3d8a24769d
Use checkout for ctr_firm_builder. 2023-05-02 02:19:00 +02:00
profi200 1e5e1ea6a9
Updated workflow. 2023-05-02 02:03:58 +02:00
profi200 5e103deecc
Updated libn3ds to work around a hardware bug. 2022-08-15 00:35:09 +02:00
profi200 80f48ca43e
Added inih as submodule as well. 2022-07-25 15:17:23 +02:00
profi200 a70673dea7
Added lgyFbScaler tool for experiments with hardware scaling. 2022-07-24 18:11:24 +02:00
profi200 99d6b1e1ea
Use latest libn3ds with fixed paths. 2022-07-24 17:45:08 +02:00
profi200 6298503e6b
Moved libn3ds to libraries/libn3ds.
Include libn3ds license in releases and nightlies.
2022-07-24 16:50:20 +02:00
profi200 cdacbc7dc5
Use a special makefile rule to avoid unpacking the release archive and p7zip dependency. 2022-07-24 15:53:41 +02:00
profi200 edaa5fb2cb
Don't limit make to 4 jobs. 2022-07-24 15:18:37 +02:00
profi200 d80588ffc4
Limit the clone depth for faster CI builds. 2022-07-24 03:40:28 +02:00
profi200 93d5cdf045
Moved open_agb_firm specific error codes and error printing out of libn3ds. 2022-07-24 01:52:03 +02:00
profi200 45830c8c68
Forgot to mention the Actions tab. 2022-07-16 15:02:00 +02:00
profi200 c171c4da1d
Added nightly build link. 2022-07-16 14:09:25 +02:00
profi200 b1739994a2
Clean up CI script.
And don't embed commit hash in artifact name.
2022-07-16 13:53:25 +02:00
profi200 6bfccaee80
Testing GitHub Actions. 2022-07-15 19:45:03 +02:00
profi200 b710d8e326
Updated libn3ds.
Renamed thirdparty to libraries.
2022-07-14 03:00:31 +02:00
spitzeqc 834c0ffbbf
Added IPS and UPS patch support (#75) 2022-07-14 02:46:37 +02:00
profi200 b1d2b5a84a
Updated libn3ds. 2022-07-03 01:38:56 +02:00
profi200 09622b88f8
Corrected clone instructions. 2022-07-03 01:32:54 +02:00
profi200 48448c749c
Added repo clone/update instructions 2022-06-29 16:37:34 +02:00
profi200 a13499c49e
Fixed README.md for latest changes. 2022-06-29 16:06:07 +02:00
profi200 1fe529f4c5
Overhauled brightness control. 2022-06-29 15:58:09 +02:00
profi200 bd6bc4fd54
Removed hardcoded libn3ds. 2022-06-29 15:55:07 +02:00
spitzeqc ee21e3edb0 Changed backlight power to use GFX_powerOffBacklights() and moved brightness control to 'main' function 2022-06-28 00:41:14 +02:00
spitzeqc 6b5abf383d Added ability to turn screen on and off 2022-06-28 00:41:14 +02:00
spitzeqc 56bf27a026 Added brightness adjustment in-game 2022-06-28 00:41:14 +02:00
profi200 3183839120
Ported toshsd and sdmmc drivers for DSi. 2022-06-24 00:24:44 +02:00
profi200 5ab356a248
Minor toshsd/sdmmc driver code cleanup/improvement. 2022-06-23 15:21:01 +02:00
profi200 9bd9497315
Fixed glitches when taking screenshots. This should also fix freezes.
Screenshots now have the date and time in the file name.
2022-06-20 20:03:46 +02:00
profi200 25b1f794c2
Fixed/improved documentation.
Made triggering the screenshot feature easier. Exact timing is no longer required when pressing SELECT + Y. However the screenshot feature may cause graphic glitches. This will be fixed later.
2022-06-20 18:10:25 +02:00
profi200 9e44587f1c
Simplified clock management for toshsd/sdmmc drivers. 2022-06-08 20:22:54 +02:00
profi200 dbaad7d09c
Major overhaul of (e)MMC/SD card driver including high capacity (e)MMC support (untested).
Various small bug fixes and documentation improvement.
Other, unrelated bug fixes/changes.
2022-06-01 19:30:52 +02:00
profi200 4e86b0c6bf
Fixed error detection on file write. 2022-05-22 23:47:07 +02:00
profi200 b128dd4575
Do not power off if an error occurs while powering off. 2022-05-22 21:12:34 +02:00
profi200 a588af0b3c
Fixed FatFs name in error codes. 2022-05-22 00:39:31 +02:00
profi200 dd4f51334f
Updated fatFs to R0.14b. 2022-05-22 00:13:56 +02:00
profi200 97bdad5710
Toshsd driver pretty much finished now (SDIO IRQ support missing).
Added some missing function and argument descriptions + other minor changes.
2022-05-10 19:34:27 +02:00
profi200 f486ba2b9f
Small toshsd and sdmmc driver overhaul. 2022-05-07 17:36:20 +02:00
profi200 8f86f79461
[toshsd/sdmmc] Renamed slot to card. 2022-05-01 20:56:05 +02:00
profi200 78fd101c66
Allow ROMs bigger than 32 MiB to be loaded with a warning.
Note: If any game/ROM hack tries to access data out of bounds it will crash sooner or later. Don't open issues for such ROMs.
2022-05-01 20:33:13 +02:00
profi200 c139ceb720
Allow large file reads and writes via fatfs.
Miscellaneous NDMA driver changes.
2022-05-01 20:29:25 +02:00
profi200 92f3208daa
Use asm_macros.h in both start.s files. 2022-04-29 18:25:13 +02:00
profi200 f9f47df59e
Switched to unified assembly syntax. 2022-04-28 23:38:26 +02:00
profi200 9d54442c42
SD/(e)MMC driver cleanup. 2022-04-28 17:10:43 +02:00
profi200 b8b75d784c
Fixed RTC type conversion warning. 2022-04-26 03:02:31 +02:00
profi200 5714b5eb16
Merge branch 'master' of github.com:profi200/open_agb_firm 2022-04-25 21:03:11 +02:00
profi200 dc0320615b
A bit of unplanned SHA driver optimization. Saves about 1 ms per MiB. 2022-04-23 01:45:07 +02:00
profi200 3a31110673
Fixed MCU battery level/temperature code. 2022-04-23 01:40:05 +02:00
profi200 1c680e7d52
Partial MCU driver rewrite.
Miscellaneous changes/fixes.
2022-03-29 17:29:24 +02:00
profi200 4a6603d110
Added day of week calculation for the GBA RTC. 2022-01-25 00:18:13 +01:00
profi200 2222e54f0f
Fixed a bug that may cause the file browser not to display all 1000 files.
Made file sorting faster.
Miscellaneous fixes.
2022-01-16 20:46:38 +01:00
Midnoclose 782596facd Add firmtool support 2022-01-09 15:14:18 +01:00
profi200 a9fcf853bb
Forgot a newline while changing the default config in previous commit. Fixes #53. 2022-01-05 16:19:46 +01:00
profi200 9756e2eafc
Added configurable scaling. Very hacky implementation because no citro3d and DMA-330 JIT. 2022-01-05 00:01:03 +01:00
profi200 15cf1bffd5
Added per-game config support. Place "romName.ini" in "/3ds/open_agb_firm/saves" to change per-game settings. Currently only saveSlot is configurable.
Updated README.md.
2021-12-21 19:40:16 +01:00
profi200 247cb19cb5
Actually screw the useSaveFolder config. "/3ds/open_agb_firm/saves" is the new location for savegames and future per-game configs.
Added code for savegame slots. Currently not configurable.
2021-12-19 19:27:52 +01:00
profi200 35243abed0
Updated README for commit d7baad122a.
Added a README note on the crappy sound.
2021-12-19 00:02:53 +01:00
profi200 37f3df4a52
Added autoboot. Place "autoboot.txt" in "/3ds/open_agb_firm".
Note: The autoboot path must be a single line starting with "sdmc:/".
2021-12-18 23:45:51 +01:00
profi200 d7baad122a
Renamed a few config options and added a savegame path one (currently non-functional).
Moved config parsing and backlight setup to an earlier location.
Misc changes.
2021-12-18 03:04:25 +01:00
profi200 b09e3a0eee
Bump file browser entry limit to 1000 files and folders. Please note that the real limit is dynamic and depends on file name lengths. Fixes #37. 2021-12-16 18:33:49 +01:00
profi200 6129451b75
Code size reduction + slightly more readable code in setupSaveType(). 2021-12-13 02:12:53 +01:00
profi200 f59f596a2b
Make the ARM9 fast again. 2021-12-09 18:33:00 +01:00
profi200 434f714ef1
Fixed white screen issues with save type none games. Fixes #48. 2021-12-09 13:22:39 +01:00
profi200 82d54b341c
Force DWARF 4 debug symbols for now. 2021-12-09 00:34:52 +01:00
profi200 fa4ef131d9
Moved tests over to libn3ds. 2021-11-07 14:05:47 +01:00
profi200 2308e59c85 Begin separating oaf into lib and FIRM. Removed unnecessary config.ini file. 2021-11-07 13:55:59 +01:00
HTV04 67f42f764c Re-implement checkSaveOverride
Based on #40
2021-11-07 13:55:59 +01:00
HTV04 1375224a6e Post-review changes 2021-11-07 13:55:59 +01:00
Harrison 83fe7a9961 More finishing touches 2021-11-07 13:55:59 +01:00
Harrison 6899a7a892 Finishing touches 2021-11-07 13:55:59 +01:00
Harrison eee47c5de1 Full gba_db.bin integration and other changes 2021-11-07 13:55:59 +01:00
Harrison 157a973006 Finally fixed builder script and gba_db.bin
The generated gba_db.bin now works with open_agb_firm!

With a ton of help from profi200, I finally figured out the issue. Turns out open_agb_firm uses a binary search algorithm to find the hash from the gba_db.bin file. After a ton of (probably unnecessary) trial and error, I fixed my script so that it sorts the entries in the way open_agb_firm expects, and boom, it works!
2021-11-07 13:55:59 +01:00
Harrison 1ad3dcc0ef Changed backlightRange to maxBacklight
See updated README for more details.
2021-11-07 13:55:59 +01:00
Harrison d2e1159113 Revert ZIP changes 2021-11-07 13:55:59 +01:00
Harrison f5b40f1156 Added backlightRange option and changed how backlight limit works
Small commit, but a few big changes:
* Added an "Advanced" section to the config that contains options for advanced users, including a new option, "backlightRange."
  * The backlightRange option changes the backlight limits, and has three different modes (0-2): Recommended, Old 3DS, and New 3DS. The latter two are based on the min and max backlight limits for the normal 3DS mode. See the updated README for more information.
* Revamped how the backlight limit works, not only to work with the new backlightRange option, but also to improve how it works.
  * GFX_setBrightness no longer sets the limit for the backlight setting, completely removing its restrictions. The limit is now handled by open_agb_firm.c, and has a new "minimum" to prevent too low values. A fail-safe for the backlight option has also been implemented to prevent unintended side effects, such as the backlight being set to 0 when it's set to a value above the maximum limit.
* Updated README to reflect changes, among other changes.

Other changes:
* Replace 7Z files in gitignore with ZIP files.
2021-11-07 13:55:59 +01:00
Harrison 675db2942f A ton of changes
* Updated gba_db.bin Builder to v2.1, adding some important fail-safes and fixing some nasty bugs.
* Updated Makefile to create releases as ZIPs instead of 7Zs and include the gba_db.bin file in releases.
* Updated gitignore to allow necessary files for gba_db.bin Builder to be added to the repo, among other changes.
* Moved script and necessary files to a new "tools" folder. The resources folder is now used for files that facilitate releases, such as "safe" versions of gba_db.bin.
* Made a few changes to open_agb_firm.c to prepare for full gba_db.bin integration.
* Updated README to reflect the new changes, among other changes.
2021-11-07 13:55:59 +01:00
Harrison c4f6f3dabe open_agb_firm gba_db.bin Builder v2.0 and other changes
open_agb_firm gba_db.bin Builder:
* Updated to v2.0
* No-Intro DAT support
* Additional entry support
* Entries added/skipped are now output
* Other optimizations

Other changes:
* Remove most overrides in `open_agb_firm.c` to prepare for gba_db.bin
* Add `resources/gba.dat` entry to gitignore
2021-11-07 13:55:59 +01:00
Harrison 2c8db472ab Fix save type detection bug
Fixed dumb mistake that caused the save type to always be returned as 15 OOPS

Also added/changed some comments
2021-11-07 13:55:59 +01:00
Harrison 76092e9093 gba_db_builder Improvements
Also fix gba_db.bin
2021-11-07 13:55:59 +01:00
Harrison 6538c56106 Add gba_db_builder 2021-11-07 13:55:59 +01:00
Harrison 167db2f20d Add more exception entries 2021-11-07 13:55:59 +01:00
Harrison 7f3c6762c7 Change brightness limit
Based on GodMode9's brightness limit, 107.

The previous limit was way too dark, especially in sunlight. Even though brightness control hasn't been added yet, I still think it's better to give users the option.
2021-11-07 13:55:59 +01:00
Harrison b972f75adf Add more save type exception entries
Also remove "Confirmed" status from EEPROM types because they all vary between 4k/8k and 64k.
2021-11-07 13:55:59 +01:00
gecko caca936a66 Add homebrew save type overrides (#40) 2021-11-07 13:55:59 +01:00
profi200 a9881d3a32 Added CODEC headset detection/selction reg and bit defines. 2021-11-07 13:55:59 +01:00
profi200 3fe3f2cbba Use performance monitor bit defines in start.s. 2021-11-07 13:55:59 +01:00
profi200 ed91a742f1 Unorganized commit collecting many changes from the last months incoming. Yeah, i should have split this. 2021-11-07 13:55:59 +01:00
Harrison 3ef62b0ac1 README improvements (#33) 2021-11-07 13:55:59 +01:00
profi200 a6756d6115 Converted most I/O reg defines to structs for better optimization. 2021-11-07 13:55:59 +01:00
profi200 db12bb5ab2 Updated cfg9.h and everything relying on it based on recent findings/3dbrew. 2021-11-07 13:55:59 +01:00
profi200 d5e3a08f99 Oops. 2021-11-07 13:55:59 +01:00
profi200 c3a1458541 Some cleanup and updates based on recent 3dbrew edits. 2021-11-07 13:55:59 +01:00
profi200 8e5562a9f7 Make scaling easier to configure at compile time. 2021-11-07 13:55:59 +01:00
profi200 f7785c67e8 Added 1:1 scaling support. 2021-11-07 13:55:59 +01:00
profi200 2224e23022 Use SELECT + Y for screenshots.
Bump copyright dates and add missing copyright notices.
2021-11-07 13:55:59 +01:00
profi200 c2a9cde160 SELECT + Y for screenshots to make it harder to accidentally make them.
Include fatfs and inih licenses in release archive.
2021-11-07 13:55:59 +01:00
profi200 bf47990240 Small fixes/cleanup. 2021-11-07 13:55:59 +01:00
profi200 07c489865c Moved lots of code out of main.c/cleanup. 2021-11-07 13:55:59 +01:00
profi200 d709c76b06 Fixed the oversaturation in the output by using a lower gamma. This is roughly tuned for launch day o3DS. If you want the previous colors back set inGamma to 2.2 and outGamma to 1.21.
Make path creation faster in case it already exists.
2021-11-07 13:55:59 +01:00
profi200 9553fcbbdb Use relative paths where possible. 2021-11-07 13:55:59 +01:00
profi200 57844df7fc Added some filter options to the config. 2021-11-07 13:55:59 +01:00
profi200 5af5a65bc7 Updated fatfs to R0.14. 2021-11-07 13:55:59 +01:00
profi200 ac429d2e4b Added basic config file support (thanks to benhoyt for his inih lib). 2021-11-07 13:55:59 +01:00
profi200 f2fb5a62b3 Enabled more debugging techniques by default in debug builds.
Added more Arm intrinsics.
ARM7 stub now waits for REG_VCOUNT == 126 (same as after BIOS intro).
Enable ROM mirroring for all 8 Mbit games instead of just Classic NES Series.
Other misc. changes.
2021-11-07 13:55:59 +01:00
profi200 d5671a39d6 Avoid errors when the last ROM launch dir doesn't exist anymore.
Other small fixes.
2021-11-07 13:55:59 +01:00
profi200 ff8ebb9ff6 Added returning to the last dir a ROM was launched from on next boot. Fixes #21. 2021-11-07 13:55:59 +01:00
profi200 d22a248b40 Some small, unimportant changes. 2021-11-07 13:55:59 +01:00
profi200 b5ab37cb2c Made the file browser sorting a bit faster. 2021-11-07 13:55:59 +01:00
profi200 411aa70b0f Fixed file browser sorting. 2021-11-07 13:55:59 +01:00
profi200 36cc930c1f Port some of the changes from arm_intrinsic.h to arm.h. 2021-11-07 13:55:59 +01:00
profi200 92ddc5e61b Added a basic screenshot feature dumping the GPU input texture by pressing Y. Fixes #19. 2021-11-07 13:55:59 +01:00
profi200 d7cfb126ec Added game database search code (and a debug menu for it).
Mimic ROM "open bus" (not 100% accurate) and ROM mirroring. Fixes #20.
Implemented some useful ARM instruction intrinsics.
2021-11-07 13:55:59 +01:00
profi200 a5ae7762f7 Added a temporary workaround to prevent panics if booted from bootloaders with broken screen init. 2021-11-07 13:55:59 +01:00
profi200 e2c295d784 Use anonymous structs instead of void for public kernel API. 2021-11-07 13:55:59 +01:00
profi200 8a6e9cdac9 More cleanup and bug fixes. 2021-11-07 13:55:59 +01:00
profi200 ee96be075c Added a workaround for a minor scheduling bug + documentation. 2021-11-07 13:55:59 +01:00
profi200 529c9535f2 Refactor. Moved code outside of the hardware drivers that doesn't belong there. 2021-11-07 13:55:59 +01:00
profi200 794111d802 First public release of my tiny kernel. 2021-11-07 13:55:59 +01:00
164 changed files with 3935 additions and 42929 deletions

52
.github/workflows/c-cpp.yml vendored Normal file
View File

@ -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

20
.gitignore vendored
View File

@ -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*.*

9
.gitmodules vendored Normal file
View File

@ -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

View File

@ -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
View File

@ -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

View File

@ -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
#---------------------------------------------------------------------------------------

View File

@ -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 :=

View File

@ -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__

View File

@ -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);

89
include/arm11/bitmap.h Normal file
View File

@ -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

76
include/arm11/config.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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" : :);
}*/

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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},
};

View File

@ -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

View File

@ -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.

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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.
///@}

View File

@ -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)))

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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];
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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))

View File

@ -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))

View File

@ -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);
}

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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");
}

View File

@ -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

View File

@ -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[];

View File

@ -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))

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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))

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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!

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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);
}

1
libraries/inih Submodule

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

1
libraries/libn3ds Submodule

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

BIN
resources/gba_db.bin Normal file

Binary file not shown.

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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();
};

View File

@ -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();
}

323
source/arm11/config.c Normal file
View File

@ -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;
}

View File

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

View File

@ -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);
}*/

View 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 = &REG_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 = &REG_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

View File

@ -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

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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));
}

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}*/

View File

@ -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*)&REG_GPIO1_DAT, (vu16*)&REG_GPIO2_DAT, &REG_GPIO2_DAT2, &REG_GPIO3_DAT, &REG_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);
}*/

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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(&REGs_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);
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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