You've already forked dspico-firmware
mirror of
https://github.com/LNH-team/dspico-firmware.git
synced 2026-01-09 16:28:22 -08:00
Initial commit
This commit is contained in:
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.bin binary
|
||||
51
.gitignore
vendored
Normal file
51
.gitignore
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
# Ignore build directories #
|
||||
############################
|
||||
Debug/
|
||||
Release/
|
||||
build/
|
||||
out/
|
||||
|
||||
# Compiled source #
|
||||
###################
|
||||
*.com
|
||||
*.class
|
||||
*.dll
|
||||
*.d
|
||||
*.map
|
||||
*.o
|
||||
*.so
|
||||
|
||||
# Packages #
|
||||
############
|
||||
# it's better to unpack these files and commit the raw source
|
||||
# git has its own built in compression methods
|
||||
*.7z
|
||||
*.dmg
|
||||
*.gz
|
||||
*.iso
|
||||
*.jar
|
||||
*.rar
|
||||
*.tar
|
||||
*.zip
|
||||
|
||||
# Logs and databases #
|
||||
######################
|
||||
*.log
|
||||
*.sql
|
||||
*.sqlite
|
||||
|
||||
# OS generated files #
|
||||
######################
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
*.nds
|
||||
*.elf
|
||||
*.a
|
||||
.vscode/
|
||||
roms/*.nds
|
||||
data/uartBufv060.bin
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "pico-sdk"]
|
||||
path = pico-sdk
|
||||
url = https://github.com/raspberrypi/pico-sdk.git
|
||||
90
CMakeLists.txt
Normal file
90
CMakeLists.txt
Normal file
@@ -0,0 +1,90 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
#set(PICO_SDK_PATH "../FIRMWARE/pico-sdk") # enable this if vscode or cmake complains about PICO_SDK_PATH not being set
|
||||
include(pico_sdk_import.cmake)
|
||||
project(DSpico_project C CXX ASM)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
pico_sdk_init()
|
||||
add_compile_definitions(DSpico
|
||||
PICO_STACK_SIZE=0x600
|
||||
PICO_CORE1_STACK_SIZE=0x400
|
||||
ENABLE_R4_MODE
|
||||
#DSPICO_ENABLE_WRFUXXED # This macro enables the WRFUXXED exploit to work.
|
||||
# ENABLE_PREVENT_DSI_AUTOBOOT # meant to be used with WRFU, doesn't work properly on the 3ds
|
||||
)
|
||||
|
||||
add_executable(DSpico
|
||||
src/main.cpp
|
||||
src/common.h
|
||||
src/romData.S
|
||||
src/romData.h
|
||||
src/blowfish.c
|
||||
src/blowfish.h
|
||||
src/powerSaving.c
|
||||
src/powerSaving.h
|
||||
src/scrambler.c
|
||||
src/scrambler.h
|
||||
src/scramblerRing.c
|
||||
src/scramblerRing.h
|
||||
src/ntrCardRom.c
|
||||
src/ntrCardRom.h
|
||||
src/ntrCardRomNorm.c
|
||||
src/ntrCardRomSecure.c
|
||||
src/ntrCardRomGame.c
|
||||
src/ntrCardRomGame.h
|
||||
src/ntrCardRomGameNoScramble.c
|
||||
src/ntrCardRomGameNoScramble.h
|
||||
src/ntrCardRomGameSd.cpp
|
||||
src/ntrCardRomGameR4.cpp
|
||||
src/ntrCardRomGameUsb.cpp
|
||||
src/ntrCardRomGameUsb.h
|
||||
src/usbEventQueue.c
|
||||
src/usbEventQueue.h
|
||||
src/tinyusb/dcd_rp2040.c
|
||||
src/tinyusb/rp2040_usb.c
|
||||
src/tinyusb/rp2040_usb.h
|
||||
src/tinyusb/dcd.h
|
||||
src/tinyusb/tusb_option.h
|
||||
src/tinyusb/tusb_compiler.h
|
||||
src/tinyusb/tusb_common.h
|
||||
src/tinyusb/tusb_config.h
|
||||
src/tinyusb/tusb_mcu.h
|
||||
src/tinyusb/tusb_verify.h
|
||||
src/tinyusb/tusb_types.h
|
||||
src/tinyusb/tusb_debug.h
|
||||
src/tinyusb/osal.h
|
||||
src/tinyusb/osal_none.h
|
||||
src/ntrCardSpiUart.c
|
||||
src/ntrCardSpiUart.h
|
||||
src/wrfuxxed.h
|
||||
src/wrfuxxed.S
|
||||
src/xor.S
|
||||
src/xor.h
|
||||
src/ntrCardIrq.S
|
||||
src/r4.h
|
||||
src/sd/rp2040_sdio.cpp
|
||||
src/sd/rp2040_sdio.h
|
||||
src/sd/SdCardInfo.h
|
||||
src/sd/SdCardInfo.h
|
||||
src/sd/SdCard.cpp
|
||||
src/sd/fatfs/diskio.cpp
|
||||
src/sd/fatfs/diskio.h
|
||||
src/sd/fatfs/ff.c
|
||||
src/sd/fatfs/ff.h
|
||||
src/sd/fatfs/ffconf.h
|
||||
src/sd/fatfs/ffunicode.c
|
||||
src/sd/fatfs/ffsystem.c
|
||||
)
|
||||
|
||||
if(EXISTS "${CMAKE_SOURCE_DIR}/roms/default.nds" AND EXISTS "${CMAKE_SOURCE_DIR}/roms/dsimode.nds")
|
||||
target_compile_definitions(DSpico PRIVATE
|
||||
DETECT_CONSOLE_TYPE # This macro enables the firmware to switch the rom based on which console is detected. You shouldn't change this.
|
||||
)
|
||||
endif()
|
||||
|
||||
pico_generate_pio_header(DSpico ${CMAKE_CURRENT_LIST_DIR}/src/ntrCard.pio)
|
||||
pico_generate_pio_header(DSpico ${CMAKE_CURRENT_LIST_DIR}/src/sd/rp2040_sdio.pio)
|
||||
|
||||
pico_enable_stdio_uart(DSpico 1)
|
||||
pico_add_extra_outputs(DSpico)
|
||||
target_link_libraries(DSpico pico_stdlib hardware_pio hardware_dma pico_multicore)
|
||||
17
LICENSE.txt
Normal file
17
LICENSE.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
Copyright (c) 2025 LNH team
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
134
README.md
Normal file
134
README.md
Normal file
@@ -0,0 +1,134 @@
|
||||
# DSpico Firmware
|
||||
This is the repository for the DSpico firmware. The firmware emulates a DS cartridge, with extended features for SD access and USB. PIO is used for an SDIO interface for the SD card and for interfacing the DS cartridge bus.
|
||||
|
||||
For an overview of the supported card commands, see [commands.md](docs/commands.md).
|
||||
|
||||
## Features
|
||||
- Emulates a retail DS(i) cartridge
|
||||
- Interfaces with an SD card using SDIO and exposes card commands to access it from the DS side
|
||||
- Exposes card commands to the DS side to allow interfacing with the USB port of the RP2040
|
||||
- Can emulate an R4 to support software such as the Wood R4 kernel
|
||||
- Supports having a separate rom for DS and DSi/3DS systems
|
||||
- Supports emulating the IS-SPI-USB-ADAPTER for the WRFUxxed exploit
|
||||
- Easy updating; starting the firmware with an ejected SD card reboots to BOOTSEL
|
||||
- Optimized for minimal power use when idle
|
||||
|
||||
## Pinout
|
||||
| **Peripheral** | **Pin name - Peripheral** | **Pin name - RP2040** |
|
||||
|-------------|-----------------------|-------------------|
|
||||
| **DS Slot** | D0 | GPIO12 |
|
||||
| | D1 | GPIO13 |
|
||||
| | D2 | GPIO14 |
|
||||
| | D3 | GPIO15 |
|
||||
| | D4 | GPIO16 |
|
||||
| | D5 | GPIO17 |
|
||||
| | D6 | GPIO18 |
|
||||
| | D7 | GPIO19 |
|
||||
| | CLK_DS | GPIO11 |
|
||||
| | ROM_CS | GPIO10 |
|
||||
| | SPI_CS | GPIO21 |
|
||||
| | IRQ | GPIO20 |
|
||||
| | RST_DS | GPIO09 |
|
||||
| **SDIO** | CLK_SD | GPIO03 |
|
||||
| | DAT0 | GPIO05 |
|
||||
| | DAT1 | GPIO06 |
|
||||
| | DAT2 | GPIO07 |
|
||||
| | DAT3 | GPIO08 |
|
||||
| | CMD | GPIO04 |
|
||||
|
||||
## Setup & configuration
|
||||
We recommend using WSL (Windows Subsystem for Linux), or a Unix-based machine to compile this repository.
|
||||
The steps provided will assume a Linux environment. Alternatively, you can run the `setup_environment.sh` bash script.
|
||||
|
||||
1. Run `sudo apt update && sudo apt install cmake gcc-arm-none-eabi build-essential git`
|
||||
2. Clone this repository
|
||||
3. Run the following commands:
|
||||
```bash
|
||||
git submodule update --init
|
||||
cd pico-sdk
|
||||
git submodule update --init
|
||||
cd ..
|
||||
```
|
||||
Note that you shouldn't use `--recursive` because it draws in a lot of unnecessary submodules inside the pico-sdk.
|
||||
|
||||
### CMakeList
|
||||
The `CMakeList.txt` file contains a couple of options that you can configure.
|
||||
|
||||
* `ENABLE_R4_MODE` - Enables R4 emulation. This allows you to use R4 software, such as the Wood R4 kernel. As R4 emulation can be used together with regular DSpico software, it can usually be kept enabled.
|
||||
* Note that to be able to use R4 software, your SD card must be at most 4 GB, or have a single partition in the first 4 GB of the SD card. R4 card commands cannot address SD sectors above 4 GB!
|
||||
* `DSPICO_ENABLE_WRFUXXED` - Enables emulation of the IS-SPI-USB-ADAPTER to support the WRFUxxed exploit. This requires <code>uartBufv060.bin</code> to be placed in the `data/` folder.
|
||||
* `ENABLE_PREVENT_DSI_AUTOBOOT` - Experimental feature that prevents DSi consoles from autobooting when the autoboot flag is set. It was intended to be used with WRFU Tester, which has the autoboot flag set. It is generally not recommended to use this, as it does not work properly with the 3DS and has not been tested much.
|
||||
|
||||
### Setting up the rom(s)
|
||||
To compile and properly use the firmware, you will need to place a valid DS rom in the `roms/` folder, named `default.nds`. Additionally, you may include a second rom in the `roms/` folder named `dsimode.nds`, if you wish to have a different rom for DS consoles and DSi/3DS consoles.
|
||||
<table>
|
||||
<tr>
|
||||
<th>Usage</th>
|
||||
<th>default.nds</th>
|
||||
<th>dsimode.nds</th>
|
||||
<th>Notes</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Single rom for DS and/or DSi</td>
|
||||
<td>Your rom</td>
|
||||
<td>-</td>
|
||||
<td>The rom must contain NTR blowfish keys.<br>If the rom is hybrid or DSi exclusive, it must additionally contain TWL blowfish keys.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Hybrid bootloader</td>
|
||||
<td>Bootloader</td>
|
||||
<td>-</td>
|
||||
<td>The bootloader rom must be patched with the DSpico DLDI.<br>The bootloader rom must contain NTR and TWL blowfish keys.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>DSi ntrboot</td>
|
||||
<td>GCD rom</td>
|
||||
<td>-</td>
|
||||
<td>The rom must contain GCD blowfish keys and must be properly signed.<br>The DSpico must be using USB power, such that the firmware is booted before starting the DSi. Without external power, the firmware currently does not boot fast enough to keep up with DSi ntrboot.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>3DS ntrboot</td>
|
||||
<td>3DS ntrboot rom</td>
|
||||
<td>-</td>
|
||||
<td>A 3DS ntrboot rom consists of a header, the blowfish keys and the firm to boot.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Separate rom for DS and DSi</td>
|
||||
<td>Your DS rom</td>
|
||||
<td>Your DSi rom</td>
|
||||
<td>The DS rom must contain NTR blowfish keys.<br>The DSi rom must contain both NTR and TWL blowfish keys.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>WRFUxxed</td>
|
||||
<td>Bootloader</td>
|
||||
<td>WRFU Tester v0.60</td>
|
||||
<td>The bootloader rom and <code>uartBufv060.bin</code> must be patched with the DSpico DLDI.<br><code>uartBufv060.bin</code> must be placed in the <code>/data</code> folder.<br>The bootloader rom must contain NTR blowfish keys.<br>The <code>DSPICO_ENABLE_WRFUXXED</code> define in <code>CMakeLists.txt</code> must be enabled.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Compiling
|
||||
Simply run `./compile.sh` to compile the firmware. Once it is complete, you will be able to find `DSpico.uf2` in the `build/` folder, which you can use to flash your DSpico board with.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> The firmware only works correctly when build with optimization. Recommended is `RelWithDebInfo`.
|
||||
|
||||
## License
|
||||
|
||||
The firmware for the DSpico project includes code that is licensed under the following:
|
||||
|
||||
SPDX-License-Identifier: Zlib
|
||||
- Miscellaneous source files
|
||||
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
- Pico SDK
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
- ZuluSCSI
|
||||
|
||||
For details, see the `license` directory, as well as `LICENSE.txt`.
|
||||
|
||||
## Contributors
|
||||
- [@Gericom](https://github.com/Gericom)
|
||||
- [@XLuma](https://github.com/XLuma)
|
||||
- [@Dartz150](https://github.com/Dartz150)
|
||||
- [@pedro-javierf](https://github.com/pedro-javierf)
|
||||
34
compile.sh
Normal file
34
compile.sh
Normal file
@@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
###############################################################
|
||||
# File: compile.sh
|
||||
# Creation Date: 10/11/2022 (DD/MM/YYYY)
|
||||
# Description: All-in-one script to update, setup and
|
||||
# build the DSpico firmware.
|
||||
#
|
||||
# Author: pedro-javierf
|
||||
# Copyright: LNH team (c) 2022, all rights reserved
|
||||
################################################################
|
||||
|
||||
|
||||
echo "[>] Configuring project with CMake.."
|
||||
|
||||
# Clean previous build/ folders if they exist
|
||||
rm -rf build/
|
||||
mkdir build
|
||||
|
||||
# Export the SDK Path before running CMAKE
|
||||
export PICO_SDK_PATH=../pico-sdk
|
||||
|
||||
# Specify CMAKE where we want the build tree to be at.
|
||||
# In our case, the build/ directory.
|
||||
# The source directory will be . (the current directory,
|
||||
# where the CMakeLists.txt is located).
|
||||
cmake -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo -B build/ .
|
||||
|
||||
echo "[>] Building FIRMWARE: "
|
||||
|
||||
# Go and build the firmware
|
||||
cd build
|
||||
make
|
||||
|
||||
echo "[>] Build completed. Find the DSpico.uf2 file inside build/ folder"
|
||||
0
data/.gitkeep
Normal file
0
data/.gitkeep
Normal file
396
docs/commands.md
Normal file
396
docs/commands.md
Normal file
@@ -0,0 +1,396 @@
|
||||
# Supported commands
|
||||
This page describes the card commands supported by the DSpico firmware. It is recommended to use at least 4 latency cycles for commands that read data (DSpico -> DS) and at least 8 latency cycles for commands that write data (DS -> DSpico). Normally a 6.7 MHz clock should be used.
|
||||
|
||||
## Normal mode
|
||||
When the cartridge boots, or after a card reset, the cartridge is in normal mode.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Command</th>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>00 xx xx xP PP xx xx xx</code></td>
|
||||
<td><code>NTR_CMD_ID_NORMAL_READ_PAGE</code></td>
|
||||
<td>Reads a rom header page (512 bytes).<br><code>PPP</code> must be a multiple of 512.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>3C xx xx xx xx xx xx xx</code></td>
|
||||
<td><code>NTR_CMD_ID_NORMAL_CHANGE_MODE_NTR</code></td>
|
||||
<td>Switches to NTR secure mode.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>3D xx xx xx xx xx xx xx</code></td>
|
||||
<td><code>NTR_CMD_ID_NORMAL_CHANGE_MODE_TWL</code></td>
|
||||
<td>Switches to TWL secure mode.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>71 xx xx xx xx xx xx xx</code></td>
|
||||
<td><code>NTR_CMD_ID_NORMAL_3DS_DETECT</code></td>
|
||||
<td>Ignored, but used for console type detection.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>90 xx xx xx xx xx xx xx</code></td>
|
||||
<td><code>NTR_CMD_ID_NORMAL_READ_ID</code></td>
|
||||
<td>Reads the card id (4 bytes).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>9F xx xx xx xx xx xx xx</code></td>
|
||||
<td><code>NTR_CMD_ID_NORMAL_LOAD_TABLE</code></td>
|
||||
<td>Ignored, but used for console type detection.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Secure mode
|
||||
In secure mode the received commands are blowfish encrypted.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>NTR location</th>
|
||||
<th>TWL location</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>P table</td>
|
||||
<td><code>0x1600</code></td>
|
||||
<td><code>twlArea + 0x600</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>S boxes</td>
|
||||
<td><code>0x1C00</code></td>
|
||||
<td><code>twlArea + 0xC00</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Secure area</td>
|
||||
<td><code>0x4000</code> to <code>0x8000</code></td>
|
||||
<td><code>twlArea + 0x3000</code> to <code>twlArea + 0x7000</code></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
`twlArea` is the 16-bit value at `0x92` multiplied by `0x80000`.
|
||||
|
||||
In secure mode all commands need to be issued at least two times. The first time is used to decrypt the command. No data is returned. The second time the command is actually executed.
|
||||
<table>
|
||||
<tr>
|
||||
<th>Command</th>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>1x xx xx xx xx xx xx xx</code></td>
|
||||
<td><code>NTR_CMD_ID_SECURE_READ_ID</code></td>
|
||||
<td>Reads the card id (4 bytes).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>2S SS Sx xx xx xx xx xx</code></td>
|
||||
<td><code>NTR_CMD_ID_SECURE_READ_SEGMENT</code></td>
|
||||
<td>Reads a 4 KB secure segment.<br>Segment number <code>SSS</code> must be 4, 5, 6 or 7.<br>The command needs to be issued 9 times to get the entire segment.<br>The first time, the command is decrypted and no data is returned.<br>The next 8 times 512 bytes are returned.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>4x xx xM MM NN Nx xx xx</code></td>
|
||||
<td><code>NTR_CMD_ID_SECURE_SCRAMBLER_ON</code></td>
|
||||
<td>Enables the scrambler. <code>MMMNNN</code> is used to seed the scrambler.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Ax xx xx xx xx xx xx xx</code></td>
|
||||
<td><code>NTR_CMD_ID_SECURE_CHANGE_MODE</code></td>
|
||||
<td>Switches to game mode.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Game mode
|
||||
Game mode is the mode that is used while a DS application is running. Blowfish is no longer used and commands only need to be issued once.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Command</th>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>B7 PP PP PP PP xx xx xx</code></td>
|
||||
<td><code>NTR_CMD_ID_GAME_READ_PAGE</code></td>
|
||||
<td>Reads a rom page (512 bytes).<br><code>PPPPPPPP</code> must be a multiple of 512.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>B8 xx xx xx xx xx xx xx</code></td>
|
||||
<td><code>NTR_CMD_ID_GAME_READ_ID</code></td>
|
||||
<td>Reads the card id (4 bytes).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>FC xx xx xx xx xx xx xx</code></td>
|
||||
<td><code>NTR_CMD_ID_GAME_DISABLE_SCRAMBLING</code></td>
|
||||
<td>Switches to unscrambled game mode.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Unscrambled game mode
|
||||
In this mode no scrambling is used and the extended features of the DSpico are available. On the DS side it is recommended to set the scrambler seeds to zero, such that no scrambling is used no matter if scrambling is enabled or disabled in the control register (when the seed is zero, the scrambler only outputs zeros). By doing this, R4 specific applications will automatically not have scrambling.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Command</th>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>B7 PP PP PP PP xx xx xx</code></td>
|
||||
<td><code>NTR_CMD_ID_GAME_READ_PAGE</code></td>
|
||||
<td>Returns 512 bytes of garbage unless the <code>ENABLE_R4_MODE</code> define is used (see below).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>B8 xx xx xx xx xx xx xx</code></td>
|
||||
<td><code>NTR_CMD_ID_GAME_READ_ID</code></td>
|
||||
<td>Reads the card id (4 bytes).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>E3 xx xx xx SS SS SS SS</code></td>
|
||||
<td><code>NTR_CMD_ID_GAME_REQ_SD_READ</code></td>
|
||||
<td>Requests an SD read of sector <code>SSSSSSSS</code>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>E4 xx xx xx xx xx xx xx</code></td>
|
||||
<td><code>NTR_CMD_ID_GAME_GET_SD_STAT</code></td>
|
||||
<td>Returns 1 when the current SD operation (read or write) is complete,<br>or 0 otherwise. (4 bytes)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>E5 xx xx xx xx xx xx xx</code></td>
|
||||
<td><code>NTR_CMD_ID_GAME_GET_SD_DATA</code></td>
|
||||
<td>Returns 512 bytes of SD data that was read previously.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>E8 SS xx xx xx xx xx xx</code></td>
|
||||
<td><code>NTR_CMD_ID_GAME_USB_COMMAND</code></td>
|
||||
<td>Performs a USB command. This command has no payload data.<br>See below for the list of sub commands (<code>SS</code>).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>E9 xI PP xT LL LL LL LL</code></td>
|
||||
<td><code>NTR_CMD_ID_GAME_USB_WRITE_DATA</code></td>
|
||||
<td>Writes 512 bytes of data to an endpoint buffer.<br><code>PP</code> is the endpoint id. <code>I</code> specifies the buffer index (0 or 1).<br><code>T</code> specifies whether a transfer should be started (1) or not (0).<br><code>LLLLLLLL</code> specifies the actual data length (0 <= length <= 512).<br>Length zero is special cased to expect no payload data, for zero length transfers.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>EA xx PP xI xx xx xx xx</code></td>
|
||||
<td><code>NTR_CMD_ID_GAME_USB_READ_DATA</code></td>
|
||||
<td>Reads 512 bytes of data from an endpoint buffer.<br><code>PP</code> is the endpoint id. <code>I</code> specifies the buffer index (0 or 1).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>EB xx xx xx xx xx xx xx</code></td>
|
||||
<td><code>NTR_CMD_ID_GAME_USB_GET_EVENT</code></td>
|
||||
<td>Dequeues an event from the USB event queue and returns it (4 bytes).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>F6 E1 0D 9Q SS SS SS SS</code></td>
|
||||
<td><code>NTR_CMD_ID_GAME_WRITE_SD_DATA</code></td>
|
||||
<td>Writes 512 bytes of SD sector data. <code>Q</code> is <code>10XY</code> (binary) with<br><code>X</code> the <code>WRITE_SD_DATA_IS_FIRST_FLAG</code> indicating the start of a sequential write, and<br><code>Y</code> the <code>WRITE_SD_DATA_IS_LAST_FLAG</code> indicating the last sector of a sequential write.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### SD read
|
||||
This pseudocode illustrates how to do a (sequential) SD read. When a sector read is requested, the DSpico will automatically start reading the next sector when the read of the first sector completes. This improves throughput, as the completed sector can be transferred to the DS, while the next sector is being read from the SD card.
|
||||
```C
|
||||
read(sector, count, data)
|
||||
{
|
||||
NTR_CMD_ID_GAME_REQ_SD_READ(sector);
|
||||
do
|
||||
{
|
||||
while (NTR_CMD_ID_GAME_GET_SD_STAT() == 0);
|
||||
NTR_CMD_ID_GAME_GET_SD_DATA(data);
|
||||
} while (--count != 0);
|
||||
|
||||
while (NTR_CMD_ID_GAME_GET_SD_STAT() == 0);
|
||||
}
|
||||
```
|
||||
|
||||
### SD write
|
||||
This pseudocode illustrates how to do a (sequential) SD write. While the DSpico is writing a sector to the SD card, the next sector can already be transferred to the DSpico to improve throughput.
|
||||
```C
|
||||
write(sector, count, data)
|
||||
{
|
||||
if (count == 1)
|
||||
{
|
||||
NTR_CMD_ID_GAME_WRITE_SD_DATA(sector, first: true, last: true, data); // send 0 = last
|
||||
}
|
||||
else if (count > 1)
|
||||
{
|
||||
NTR_CMD_ID_GAME_WRITE_SD_DATA(sector, first: true, last: false, data); // send 0
|
||||
sector++;
|
||||
for (i = 1; i < count - 1; i++)
|
||||
{
|
||||
NTR_CMD_ID_GAME_WRITE_SD_DATA(sector, first: false, last: false, data); // send i
|
||||
sector++;
|
||||
while (NTR_CMD_ID_GAME_GET_SD_STAT() == 0); // wait i - 1
|
||||
}
|
||||
|
||||
NTR_CMD_ID_GAME_WRITE_SD_DATA(sector, first: false, last: true, data); // send last
|
||||
while (NTR_CMD_ID_GAME_GET_SD_STAT() == 0); // wait last - 1
|
||||
}
|
||||
|
||||
while (NTR_CMD_ID_GAME_GET_SD_STAT() == 0); // wait last
|
||||
}
|
||||
```
|
||||
|
||||
### NTR_CMD_ID_GAME_USB_COMMAND sub commands
|
||||
Most of the sub commands directly map to tinyusb functions.
|
||||
<table>
|
||||
<tr>
|
||||
<th>Command</th>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>E8 01 xx xx xx xx xx xx</code></td>
|
||||
<td><code>USB_SUB_COMMAND_INIT</code></td>
|
||||
<td>Initializes USB.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>E8 02 xx xx xx xx xx xx</code></td>
|
||||
<td><code>USB_SUB_COMMAND_BEGIN_SET_ADDRESS</code></td>
|
||||
<td><code>dcd_set_address(0, 0)</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>E8 03 xx xx xx xx xx xx</code></td>
|
||||
<td><code>USB_SUB_COMMAND_REMOTE_WAKEUP</code></td>
|
||||
<td><code>dcd_remote_wakeup(0)</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>E8 04 xx xx xx xx xx xx</code></td>
|
||||
<td><code>USB_SUB_COMMAND_CONNECT</code></td>
|
||||
<td><code>dcd_connect(0)</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>E8 05 xx xx xx xx xx xx</code></td>
|
||||
<td><code>USB_SUB_COMMAND_DISCONNECT</code></td>
|
||||
<td><code>dcd_disconnect(0)</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>E8 06 xx xx xx xx xx xx</code></td>
|
||||
<td><code>USB_SUB_COMMAND_SOF_ENABLE</code></td>
|
||||
<td><code>dcd_sof_enable(0, true)</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>E8 07 xx xx xx xx xx xx</code></td>
|
||||
<td><code>USB_SUB_COMMAND_SOF_DISABLE</code></td>
|
||||
<td><code>dcd_sof_enable(0, false)</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>E8 08 xx xx xx xx xx xx</code></td>
|
||||
<td><code>USB_SUB_COMMAND_EP_CLOSE_ALL</code></td>
|
||||
<td><code>dcd_edpt_close_all(0)</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>E8 09 PP xx xx xx xx xx</code></td>
|
||||
<td><code>USB_SUB_COMMAND_EP_STALL</code></td>
|
||||
<td><code>dcd_edpt_stall(0, PP)</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>E8 0A PP xx xx xx xx xx</code></td>
|
||||
<td><code>USB_SUB_COMMAND_EP_CLEAR_STALL</code></td>
|
||||
<td><code>dcd_edpt_clear_stall(0, PP)</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>E8 0B xx xx xx xx xx xx</code></td>
|
||||
<td><code>USB_SUB_COMMAND_EP_CLOSE</code></td>
|
||||
<td><code>dcd_edpt_close(0, PP)</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>E8 0C RR xx xx xx xx xx</code></td>
|
||||
<td><code>USB_SUB_COMMAND_FINISH_SET_ADDRESS</code></td>
|
||||
<td><code>usb_hw->dev_addr_ctrl = RR</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>E8 0D PP xT xx xx xS SS</code></td>
|
||||
<td><code>USB_SUB_COMMAND_EP_OPEN</code></td>
|
||||
<td>Opens endpoint <code>PP</code>. The endpoint will have type <code>T</code><br>(0 = control, 1 = isochronous, 2 = bulk, 3 = interrupt)<br>and maximum packet size <code>SSS</code>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>E8 0E xx xx xx xx xx xx</code></td>
|
||||
<td><code>USB_SUB_COMMAND_CLEAR_EVENT_QUEUE</code></td>
|
||||
<td>Clears the USB event queue.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>E8 0F xx xx xx xx xx xx</code></td>
|
||||
<td><code>USB_SUB_COMMAND_DEINIT</code></td>
|
||||
<td>Deinitializes USB.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>E8 10 PP xI LL LL LL LL</code></td>
|
||||
<td><code>USB_SUB_COMMAND_BEGIN_TRANSFER</code></td>
|
||||
<td>Starts a transfer on endpoint <code>PP</code>. <code>I</code> is the buffer index (0 or 1),<br>and <code>LLLLLLLL</code> is the length (0 <= length <= 512).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>E8 11 xx xx xx xx xx xx</code></td>
|
||||
<td><code>USB_SUB_COMMAND_INTERRUPT_ENABLE</code></td>
|
||||
<td><code>dcd_int_enable(0)</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>E8 12 xx xx xx xx xx xx</code></td>
|
||||
<td><code>USB_SUB_COMMAND_INTERRUPT_DISABLE</code></td>
|
||||
<td><code>dcd_int_disable(0)</code></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### R4 emulation
|
||||
The following commands are additionally supported for R4 emulation when the `ENABLE_R4_MODE` define is used. See also [r4.md](r4.md).
|
||||
<table>
|
||||
<tr>
|
||||
<th>Command</th>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>00 00 00 00 xx xx xx xx</code></td>
|
||||
<td>-</td>
|
||||
<td>Returns zero (4 bytes).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>B0 xx xx xx xx xx xx xx</code></td>
|
||||
<td>-</td>
|
||||
<td>Get R4 card info. Returns 0x1F4 (4 bytes).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>B2 PP PP PP PP xx xx xx</code></td>
|
||||
<td>-</td>
|
||||
<td>Starts a save read at address <code>PPPPPPPP</code>. The address must be 512 byte aligned. The command returns 1 while the card is busy reading, and 0 once the read is complete (4 bytes).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>B3 xx xx xx xx xx xx xx</code></td>
|
||||
<td>-</td>
|
||||
<td>Returns the 512 bytes of save data that were previously requested with command <code>B2</code>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>B4 PP PP PP PP xx xx xx</code></td>
|
||||
<td>-</td>
|
||||
<td>Initializes the cluster map for a rom (lsb of address is 0) or save file (lsb of address is 1). <code>PPPPPPPP</code> is the 2-byte aligned SD address of the FAT entry of the file. The command returns 1 while the cluster map is being initialized,<br>and 0 once complete (4 bytes).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>B6 PP PP PP PP xx xx xx</code></td>
|
||||
<td>-</td>
|
||||
<td>Starts a rom read at address <code>PPPPPPPP</code>. The address must be 512 byte aligned. The command returns 1 while the card is busy reading, and 0 once the read is complete (4 bytes).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>B7 PP PP PP PP xx xx xx</code></td>
|
||||
<td><code>NTR_CMD_ID_GAME_READ_PAGE</code></td>
|
||||
<td>Returns the 512 bytes of rom data that were previously requested with command <code>B6</code>. <code>PPPPPPPP</code> is the 512 byte aligned rom address.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>B9 PP PP PP PP xx xx xx</code></td>
|
||||
<td>-</td>
|
||||
<td>Starts an SD read at SD address <code>PPPPPPPP</code>. The address must be 512 byte aligned. The command returns 0x1F4 while the card is busy reading, and 0 once the read is complete (4 bytes).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>BA xx xx xx xx xx xx xx</code></td>
|
||||
<td>-</td>
|
||||
<td>Returns the 512 bytes of SD data that were previously requested with command <code>B9</code>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>BB PP PP PP PP xx xx xx</code></td>
|
||||
<td>-</td>
|
||||
<td>Starts an SD write to SD address <code>PPPPPPPP</code>. The address must be 512 byte aligned. The command expects 512 bytes of data to write.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>BE xx xx xx xx xx xx xx</code></td>
|
||||
<td>-</td>
|
||||
<td>Gets the status of the SD write that was started previously with command <code>BB</code>. The command returns 1 while the card is busy writing, and 0 once the write is complete (4 bytes).</td>
|
||||
</tr>
|
||||
</table>
|
||||
30
docs/r4.md
Normal file
30
docs/r4.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# R4
|
||||
This file documents the extra card commands supported by the original R4. Note that the original R4 only supported non-HC SD cards. As such the commands can only address up to 4GB on a SD card. All extra card commands for the R4 are for game mode and use the scrambler for both command and data as is usual for game mode commands. Write data (not command) send from the DS to the card appears never to be scrambled by the DS card hardware, although the scrambler state itself does advance.
|
||||
|
||||
It appears that all R4 commands use 0 cycles of initial latency (L1) and 24 cycles of page latency (L2), with the 6.7 MHz clock. Card id commands are not patched and use the timings from the retail game rom header, but without L1 latency (that's what the sdk does). Those can be as fast as a single cycle of L2 latency, depending on the game. Failing to respond to card id reads will trigger a card pull-out response in retail games. The card id should never be adapted to the retail game being played and should stay equal to the one that the console received the very first time at boot in normal mode. The actual value of the card id does not seem to matter much, as long as bit 31 reflects the protocol version that should be used.
|
||||
|
||||
* `0000000000000000` - No idea what it does, sending back `0x00000000` works.
|
||||
* `B000000000000000` - Get card info. Normally returns `0x000001F4`.
|
||||
* The dldi driver checks for `(cardInfo & 7) == 4` in the `isInserted` function.
|
||||
* `B2XXXXXXXX000000` - Start save read at address `0xXXXXXXXX`.
|
||||
* Address should most likely be 512 byte aligned. Returns `0x00000001` while the card is busy performing the read and `0x00000000` once the data is available. This command is polled as long as the return value is 1.
|
||||
* `B3XXXXXXXX000000` - Get save data at address `0xXXXXXXXX` that was previously requested by command `B2`.
|
||||
* Not sure if the address is actually used by the card or can be any dummy value. Returns the 512 byte block of save data.
|
||||
* `B4XXXXXXXX000000` - Sets the address (`0xXXXXXXXX`) of the FAT entry for rom (lsb of address is 0) or save (lsb of address is 1).
|
||||
* This is a 2-byte aligned SD address. Returns `0x00000001` while the card is busy initializing the cluster map and `0x00000000` once ready. This command is polled as long as the return value is 1.
|
||||
* `B6XXXXXXXX000000` - Start rom read at address `0xXXXXXXXX`.
|
||||
* Address should be 512 byte aligned. Returns `0x00000001` while the card is busy performing the read and `0x00000000` once the data is available. This command is polled as long as the return value is 1. The data can then be read with the standard `B7` command.
|
||||
* `B9XXXXXXXX000000` - Start SD read at address `0xXXXXXXXX`.
|
||||
* Address is in bytes, but should be 512 byte aligned. Returns `0x000001F4` while the card is busy performing the read and `0x00000000` once the data is available. This command is polled as long as the return value is not zero.
|
||||
* `BAXXXXXXXX000000` - Get SD data at address `0xXXXXXXXX` that was previously requested by command `B9`.
|
||||
* Not sure if the address is actually used by the card or can be any dummy value. Returns the 512 byte block of SD data.
|
||||
* `BBXXXXXXXX000000` - Start SD write to address `0xXXXXXXXX`.
|
||||
* Address is in bytes, but should be 512 byte aligned. The command expects 512 bytes of data that will be written to the SD card.
|
||||
* `BCXXXXXXXX000000` - Get SD write status.
|
||||
* Not sure if the address is actually used by the card or can be any dummy value. Returns `0x00000001` while the card is busy performing the write and `0x00000000` once done. This command is polled as long as the return value is 1.
|
||||
* `BDXXXXXXXX000000` - Start save write to address `0xXXXXXXXX`.
|
||||
* Address should most likely be 512 byte aligned. The command expects 512 bytes of data that will be written to the save.
|
||||
* `BEXXXXXXXX000000` - Get save write status.
|
||||
* Not sure if the address is actually used by the card or can be any dummy value. Returns `0x00000001` while the card is busy performing the write and `0x00000000` once done. This command is polled as long as the return value is 1.
|
||||
|
||||
When initializing the R4 for retail rom use it seems there are some `0000000000000000` dummy commands send. Not sure if that is actually needed to make it work. After that `B4` is used to initialize the cluster map for rom and save file. The save file should have already been created on the SD card by the software on the DS side. The retail game is patched by the DS side software to perform rom reads using the requesting mechanism (`B6`/`B7`) and to perform save reads and writes using the corresponding card commands (`B2`/`B3` and `BD`/`BE`) instead of SPI. The advantage of the requesting/feedback mechanism for rom reads is that the data can be read as soon as it is ready. SD cards can have varying read latency and without a feedback mechanism you'd always have to account for the worst case, which can be more than the maximum amount of latency that can be specified in the IO registers and would be awful for the performance.
|
||||
674
licenses/ZuluSCSI.txt
Normal file
674
licenses/ZuluSCSI.txt
Normal file
File diff suppressed because it is too large
Load Diff
21
licenses/pico-sdk.txt
Normal file
21
licenses/pico-sdk.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
|
||||
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 copyright holder 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 HOLDER 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.
|
||||
1
pico-sdk
Submodule
1
pico-sdk
Submodule
Submodule pico-sdk added at 6a7db34ff6
73
pico_sdk_import.cmake
Normal file
73
pico_sdk_import.cmake
Normal file
@@ -0,0 +1,73 @@
|
||||
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
|
||||
|
||||
# This can be dropped into an external project to help locate this SDK
|
||||
# It should be include()ed prior to project()
|
||||
|
||||
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
|
||||
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
|
||||
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
|
||||
endif ()
|
||||
|
||||
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
|
||||
set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
|
||||
message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
|
||||
endif ()
|
||||
|
||||
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
|
||||
set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
|
||||
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
|
||||
endif ()
|
||||
|
||||
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
|
||||
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
|
||||
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
|
||||
|
||||
if (NOT PICO_SDK_PATH)
|
||||
if (PICO_SDK_FETCH_FROM_GIT)
|
||||
include(FetchContent)
|
||||
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
|
||||
if (PICO_SDK_FETCH_FROM_GIT_PATH)
|
||||
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
|
||||
endif ()
|
||||
# GIT_SUBMODULES_RECURSE was added in 3.17
|
||||
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0")
|
||||
FetchContent_Declare(
|
||||
pico_sdk
|
||||
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
|
||||
GIT_TAG master
|
||||
GIT_SUBMODULES_RECURSE FALSE
|
||||
)
|
||||
else ()
|
||||
FetchContent_Declare(
|
||||
pico_sdk
|
||||
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
|
||||
GIT_TAG master
|
||||
)
|
||||
endif ()
|
||||
|
||||
if (NOT pico_sdk)
|
||||
message("Downloading Raspberry Pi Pico SDK")
|
||||
FetchContent_Populate(pico_sdk)
|
||||
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
|
||||
endif ()
|
||||
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
|
||||
else ()
|
||||
message(FATAL_ERROR
|
||||
"SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
|
||||
)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
|
||||
if (NOT EXISTS ${PICO_SDK_PATH})
|
||||
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
|
||||
endif ()
|
||||
|
||||
set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
|
||||
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
|
||||
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
|
||||
endif ()
|
||||
|
||||
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
|
||||
|
||||
include(${PICO_SDK_INIT_CMAKE_FILE})
|
||||
0
roms/.gitkeep
Normal file
0
roms/.gitkeep
Normal file
60
setup_environment.sh
Normal file
60
setup_environment.sh
Normal file
@@ -0,0 +1,60 @@
|
||||
#!/bin/bash
|
||||
###############################################################
|
||||
# File: setup_environment.sh
|
||||
# Creation Date: 10/11/2022 (DD/MM/YYYY)
|
||||
# Description: All-in-one script to update and setup
|
||||
# the DSpico firmware repository.
|
||||
#
|
||||
# Author: pedro-javierf
|
||||
# Copyright: LNH team (c) 2022, all rights reserved
|
||||
################################################################
|
||||
|
||||
# TODO: See if packages need to be installed
|
||||
|
||||
unameOut="$(uname -s)"
|
||||
case "${unameOut}" in
|
||||
Linux*) machine=Linux;;
|
||||
Darwin*) machine=Mac;;
|
||||
CYGWIN*) machine=Cygwin;;
|
||||
MINGW*) machine=MinGw;;
|
||||
*) machine="UNKNOWN:${unameOut}"
|
||||
esac
|
||||
|
||||
|
||||
# if linux or CYGWIN
|
||||
if [[ "$machine" == "Linux" ]]
|
||||
then
|
||||
echo "Detected Linux OS. Installing needed libs."
|
||||
sudo apt update
|
||||
sudo apt install cmake gcc-arm-none-eabi build-essential git
|
||||
fi
|
||||
|
||||
if [[ "$machine" == "Cygwin" ]]
|
||||
then
|
||||
echo "Detected Cygwin. Installing needed libs."
|
||||
sudo apt update
|
||||
sudo apt install cmake gcc-arm-none-eabi build-essential git
|
||||
fi
|
||||
|
||||
|
||||
# if MacOS
|
||||
if [[ "$machine" == "Mac" ]]
|
||||
then
|
||||
# Install cmake
|
||||
brew install cmake
|
||||
|
||||
# Install the arm eabi toolchain
|
||||
brew tap ArmMbed/homebrew-formulae
|
||||
brew install arm-none-eabi-gcc
|
||||
|
||||
# The equivalent to build-essential on linux, you probably already have this.
|
||||
xcode-select --install
|
||||
fi
|
||||
|
||||
echo "[>] Updating pico-sdk submodule.."
|
||||
git submodule update --init -- pico-sdk/
|
||||
|
||||
echo "[>] Updating pico-sdk dependencies.."
|
||||
cd pico-sdk/
|
||||
git submodule update --init
|
||||
|
||||
28
src/blowfish.c
Normal file
28
src/blowfish.c
Normal file
@@ -0,0 +1,28 @@
|
||||
#include "common.h"
|
||||
#include "blowfish.h"
|
||||
|
||||
void bf_init(bf_context_t* context, const u32* pTable, const bf_sboxes_t* sBoxes)
|
||||
{
|
||||
context->pTable = pTable;
|
||||
context->sBoxes = sBoxes;
|
||||
}
|
||||
|
||||
u64 __time_critical_func(bf_decrypt)(const bf_context_t* context, u64 block)
|
||||
{
|
||||
const u32* pTable = context->pTable;
|
||||
const bf_sboxes_t* sBoxes = context->sBoxes;
|
||||
u32 y = block;
|
||||
u32 x = block >> 32;
|
||||
for (int i = 0x11; i >= 2; i--)
|
||||
{
|
||||
u32 z = pTable[i] ^ x;
|
||||
u32 a = sBoxes->sbox0[z >> 24];
|
||||
u32 b = sBoxes->sbox1[(u8)(z >> 16)];
|
||||
u32 c = sBoxes->sbox2[(u8)(z >> 8)];
|
||||
u32 d = sBoxes->sbox3[(u8)z];
|
||||
x = (d + (c ^ (b + a))) ^ y;
|
||||
y = z;
|
||||
}
|
||||
|
||||
return (x ^ pTable[1]) | ((u64) (y ^ pTable[0]) << 32);
|
||||
}
|
||||
38
src/blowfish.h
Normal file
38
src/blowfish.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
#include "common.h"
|
||||
|
||||
/// @brief Blowfish s boxes struct.
|
||||
typedef struct
|
||||
{
|
||||
u32 sbox0[0x100];
|
||||
u32 sbox1[0x100];
|
||||
u32 sbox2[0x100];
|
||||
u32 sbox3[0x100];
|
||||
} bf_sboxes_t;
|
||||
|
||||
/// @brief Blowfish context struct.
|
||||
typedef struct
|
||||
{
|
||||
const u32* pTable;
|
||||
const bf_sboxes_t* sBoxes;
|
||||
} bf_context_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// @brief Initializes the given blowfish \p context with the given \p pTable and \p sBoxes.
|
||||
/// @param context The blowfish context to initialize.
|
||||
/// @param pTable The p table to use.
|
||||
/// @param sBoxes The s boxes to use.
|
||||
void bf_init(bf_context_t* context, const u32* pTable, const bf_sboxes_t* sBoxes);
|
||||
|
||||
/// @brief Decrypts the given blowfish \p block using the given \p context.
|
||||
/// @param context The blowfish context to use.
|
||||
/// @param block The blowfish block to decrypt.
|
||||
/// @return The decrypted blowfish block.
|
||||
u64 bf_decrypt(const bf_context_t* context, u64 block);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
67
src/common.h
Normal file
67
src/common.h
Normal file
@@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico/time.h"
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef int8_t s8;
|
||||
typedef uint16_t u16;
|
||||
typedef int16_t s16;
|
||||
typedef uint32_t u32;
|
||||
typedef int32_t s32;
|
||||
typedef uint64_t u64;
|
||||
typedef int64_t s64;
|
||||
|
||||
typedef volatile uint8_t vu8;
|
||||
typedef volatile int8_t vs8;
|
||||
typedef volatile uint16_t vu16;
|
||||
typedef volatile int16_t vs16;
|
||||
typedef volatile uint32_t vu32;
|
||||
typedef volatile int32_t vs32;
|
||||
typedef volatile uint64_t vu64;
|
||||
typedef volatile int64_t vs64;
|
||||
|
||||
#define SD_USE_SDIO
|
||||
|
||||
#define SDIO_CLK 3
|
||||
#define SDIO_CMD 4
|
||||
#define SDIO_D0 5
|
||||
#define SDIO_D1 6
|
||||
#define SDIO_D2 7
|
||||
#define SDIO_D3 8
|
||||
|
||||
#define PIN_RST 9
|
||||
#define PIN_CEB 10
|
||||
#define PIN_WREB 11 //clk
|
||||
#define PIN_D0 12
|
||||
#define PIN_D1 13
|
||||
#define PIN_D2 14
|
||||
#define PIN_D3 15
|
||||
#define PIN_D4 16
|
||||
#define PIN_D5 17
|
||||
#define PIN_D6 18
|
||||
#define PIN_D7 19
|
||||
#define PIN_IRQ 20
|
||||
#define PIN_CS2 21
|
||||
|
||||
#define PIN_USB_VBUS 24
|
||||
|
||||
#define PIN_DEV_TX0 0
|
||||
#define PIN_DEV_RX0 1
|
||||
|
||||
#define PIN_INPUT_MASK 0x2FFE00
|
||||
|
||||
#define CARD_ID_NTR 0x800000C2
|
||||
#define CARD_ID_TWL 0xC00000C2
|
||||
|
||||
typedef void (*sd_callback_t)(uint32_t bytes_complete);
|
||||
|
||||
static inline uint millis(void)
|
||||
{
|
||||
return us_to_ms(time_us_64());
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include "sd/SdCard.h"
|
||||
extern SdCard gSdCard;
|
||||
#endif
|
||||
299
src/main.cpp
Normal file
299
src/main.cpp
Normal file
@@ -0,0 +1,299 @@
|
||||
#include "common.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/dma.h"
|
||||
#include "hardware/structs/scb.h"
|
||||
#include "pico/binary_info.h"
|
||||
#include "ntrCard.pio.h"
|
||||
#include "romData.h"
|
||||
#include "pico/multicore.h"
|
||||
#include "blowfish.h"
|
||||
#include "scrambler.h"
|
||||
#include "sd/fatfs/ff.h"
|
||||
#include "ntrCardRom.h"
|
||||
#include "ntrCardSpiUart.h"
|
||||
#include "r4.h"
|
||||
#include "sd/SdCard.h"
|
||||
#include "scramblerRing.h"
|
||||
#include "pico/bootrom.h"
|
||||
#include "hardware/xosc.h"
|
||||
#include "powerSaving.h"
|
||||
|
||||
static u32 sProgramOffset;
|
||||
FATFS sFatFs;
|
||||
SdCard gSdCard;
|
||||
static bool sIsSdCardMounted;
|
||||
|
||||
#ifdef DETECT_CONSOLE_TYPE
|
||||
static void setRomToDsiRom(void)
|
||||
{
|
||||
gNtrRomEmu.romData = gDsiRom;
|
||||
gNtrRomEmu.romSize = ((u32)gDsiRomSize + 511) & ~511;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void resetNtrCard(void)
|
||||
{
|
||||
ntrc_resetUsb();
|
||||
pwr_disableAfterBootPowerSaving();
|
||||
ntrc_setNormalMode();
|
||||
gNtrRomEmu.securePhase1 = false;
|
||||
gNtrRomEmu.cmdScramble = false;
|
||||
gNtrRomEmu.dataScramble = false;
|
||||
gComputeScrambler = false;
|
||||
gNtrRomEmu.scrRingRPtr = gScramblerRing;
|
||||
gScramblerRingWPtr = gScramblerRing;
|
||||
gNtrRomEmu.wordIdx = 0;
|
||||
gNtrRomEmu.twlMode = false;
|
||||
gNtrRomEmu.readDataDestination = nullptr;
|
||||
gNtrRomEmu.readDataCompleteHandler = nullptr;
|
||||
gNtrRomEmu.readDataLimit = 0;
|
||||
#ifdef ENABLE_R4_MODE
|
||||
ntrc_resetR4();
|
||||
#endif
|
||||
dma_channel_abort(0);
|
||||
pio_sm_set_enabled(pio0, 0, false);
|
||||
pio_sm_set_pindirs_with_mask(pio0, 0, 0, PIN_INPUT_MASK);
|
||||
pio_sm_clear_fifos(pio0, 0);
|
||||
pio_sm_restart(pio0, 0);
|
||||
pio_sm_clkdiv_restart(pio0, 0);
|
||||
irq_clear(PIO0_IRQ_0);
|
||||
irq_set_enabled(PIO0_IRQ_0, true);
|
||||
pio_sm_exec(pio0, 0, pio_encode_jmp(sProgramOffset));
|
||||
pio_sm_set_enabled(pio0, 0, true);
|
||||
#ifdef DETECT_CONSOLE_TYPE
|
||||
setRomToDsiRom();
|
||||
gNtrRomEmu.cardId = 0xC00000C2;
|
||||
#endif
|
||||
#ifdef DSPICO_ENABLE_WRFUXXED
|
||||
ntrc_resetSpiUart();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef ENABLE_PREVENT_DSI_AUTOBOOT
|
||||
static u64 sResetStart;
|
||||
#endif
|
||||
|
||||
static void __time_critical_func(gpioIrq)(uint gpio, u32 events)
|
||||
{
|
||||
#ifdef ENABLE_PREVENT_DSI_AUTOBOOT
|
||||
u64 time = time_us_64();
|
||||
#endif
|
||||
if (gpio == PIN_RST)
|
||||
{
|
||||
if (events & GPIO_IRQ_EDGE_FALL)
|
||||
{
|
||||
pio_sm_set_enabled(pio0, 0, false);
|
||||
pio_sm_set_pindirs_with_mask(pio0, 0, 0, PIN_INPUT_MASK);
|
||||
}
|
||||
if (events & GPIO_IRQ_EDGE_RISE)
|
||||
{
|
||||
resetNtrCard();
|
||||
#ifdef ENABLE_PREVENT_DSI_AUTOBOOT
|
||||
u32 resetTime = time - sResetStart;
|
||||
if (resetTime > 700000)
|
||||
pio_sm_set_enabled(pio0, 0, false);
|
||||
sResetStart = time;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void __scratch_x("cpu1") core1_entry(void)
|
||||
{
|
||||
irq_set_mask_enabled(~0u, false);
|
||||
scb_hw->scr |= M0PLUS_SCR_SLEEPDEEP_BITS;
|
||||
while (!gComputeScrambler)
|
||||
{
|
||||
gScramblerRingWPtr = gScramblerRing;
|
||||
__wfe();
|
||||
}
|
||||
while (1)
|
||||
{
|
||||
u32* wPtr = gScramblerRingWPtr;
|
||||
u32* next = SCR_RING_WRAP(wPtr + 1);
|
||||
if (next == gNtrRomEmu.scrRingRPtr)
|
||||
{
|
||||
__wfe();
|
||||
continue;
|
||||
}
|
||||
|
||||
*wPtr = scr_getNext32(&gScramblerState);
|
||||
gScramblerRingWPtr = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void initSd(void)
|
||||
{
|
||||
memset(&sFatFs, 0, sizeof(sFatFs));
|
||||
|
||||
//try mounting 16 times
|
||||
bool ok = false;
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
if (f_mount(&sFatFs, "0:", 1) == FR_OK)
|
||||
{
|
||||
ok = true;
|
||||
sIsSdCardMounted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ok)
|
||||
{
|
||||
sIsSdCardMounted = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void tryRebootToBootsel(void)
|
||||
{
|
||||
if (!sIsSdCardMounted)
|
||||
{
|
||||
xosc_init();
|
||||
reset_usb_boot(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int __time_critical_func(main)()
|
||||
{
|
||||
bi_decl(bi_program_description("Ntr card emulator"));
|
||||
bi_decl(bi_pin_mask_with_name(0xFF000, "Ntr card D0-D7"));
|
||||
bi_decl(bi_1pin_with_name(PIN_IRQ, "Ntr card irq"));
|
||||
bi_decl(bi_1pin_with_name(PIN_CEB, "Ntr card ceb (rom enable)"));
|
||||
bi_decl(bi_1pin_with_name(PIN_WREB, "Ntr card wreb (clock)"));
|
||||
bi_decl(bi_1pin_with_name(PIN_RST, "Ntr card reset"));
|
||||
bi_decl(bi_1pin_with_name(PIN_CS2, "Ntr card cs2 (spi enable)"));
|
||||
|
||||
// u64 bootTime = time_us_64();
|
||||
|
||||
// set_sys_clock_khz(/*125000*/200000, true);
|
||||
// 200 MHz = 1200 MHz / 6 / 1
|
||||
set_sys_clock_pll(1200000000, 6, 1);
|
||||
|
||||
dma_channel_claim(0);
|
||||
|
||||
memset(&gNtrRomEmu, 0, sizeof(gNtrRomEmu));
|
||||
|
||||
|
||||
// We support DSi mode if the firmware is dual mode, or if a single rom has the DSi flag set
|
||||
#ifndef DETECT_CONSOLE_TYPE
|
||||
if (gDefaultRom[0x12] & 2)
|
||||
{
|
||||
#endif
|
||||
gNtrRomEmu.cardId = CARD_ID_TWL;
|
||||
#ifndef DETECT_CONSOLE_TYPE
|
||||
}
|
||||
else
|
||||
{
|
||||
gNtrRomEmu.cardId = CARD_ID_NTR;
|
||||
}
|
||||
#endif
|
||||
|
||||
multicore_launch_core1(core1_entry);
|
||||
|
||||
gpio_init_mask(PIN_INPUT_MASK);
|
||||
gpio_set_dir_in_masked(PIN_INPUT_MASK);
|
||||
gpio_init(PIN_IRQ);
|
||||
gpio_put(PIN_IRQ, 0);
|
||||
gpio_set_dir(PIN_IRQ, GPIO_OUT);
|
||||
gpio_disable_pulls(PIN_D0);
|
||||
gpio_disable_pulls(PIN_D1);
|
||||
gpio_disable_pulls(PIN_D2);
|
||||
gpio_disable_pulls(PIN_D3);
|
||||
gpio_disable_pulls(PIN_D4);
|
||||
gpio_disable_pulls(PIN_D5);
|
||||
gpio_disable_pulls(PIN_D6);
|
||||
gpio_disable_pulls(PIN_D7);
|
||||
gpio_set_slew_rate(PIN_D0, GPIO_SLEW_RATE_FAST);
|
||||
gpio_set_slew_rate(PIN_D1, GPIO_SLEW_RATE_FAST);
|
||||
gpio_set_slew_rate(PIN_D2, GPIO_SLEW_RATE_FAST);
|
||||
gpio_set_slew_rate(PIN_D3, GPIO_SLEW_RATE_FAST);
|
||||
gpio_set_slew_rate(PIN_D4, GPIO_SLEW_RATE_FAST);
|
||||
gpio_set_slew_rate(PIN_D5, GPIO_SLEW_RATE_FAST);
|
||||
gpio_set_slew_rate(PIN_D6, GPIO_SLEW_RATE_FAST);
|
||||
gpio_set_slew_rate(PIN_D7, GPIO_SLEW_RATE_FAST);
|
||||
gpio_pull_up(PIN_CEB);
|
||||
gpio_pull_up(PIN_WREB);
|
||||
gpio_pull_down(PIN_RST);
|
||||
gpio_pull_up(PIN_CS2);
|
||||
gpio_set_drive_strength(PIN_D0, GPIO_DRIVE_STRENGTH_2MA);
|
||||
gpio_set_drive_strength(PIN_D1, GPIO_DRIVE_STRENGTH_2MA);
|
||||
gpio_set_drive_strength(PIN_D2, GPIO_DRIVE_STRENGTH_2MA);
|
||||
gpio_set_drive_strength(PIN_D3, GPIO_DRIVE_STRENGTH_2MA);
|
||||
gpio_set_drive_strength(PIN_D4, GPIO_DRIVE_STRENGTH_2MA);
|
||||
gpio_set_drive_strength(PIN_D5, GPIO_DRIVE_STRENGTH_2MA);
|
||||
gpio_set_drive_strength(PIN_D6, GPIO_DRIVE_STRENGTH_2MA);
|
||||
gpio_set_drive_strength(PIN_D7, GPIO_DRIVE_STRENGTH_2MA);
|
||||
|
||||
#ifdef DETECT_CONSOLE_TYPE
|
||||
setRomToDsiRom();
|
||||
gNtrRomEmu.isDSMode = true;
|
||||
#else
|
||||
gNtrRomEmu.romData = gDefaultRom;
|
||||
gNtrRomEmu.romSize = (u32)gDefaultRomSize;
|
||||
gNtrRomEmu.romSize = (gNtrRomEmu.romSize + 511) & ~511;
|
||||
#endif
|
||||
|
||||
sProgramOffset = pio_add_program(pio0, &ntr_card_program);
|
||||
#ifdef DSPICO_ENABLE_WRFUXXED
|
||||
u32 spiUartProgOffs = pio_add_program(pio0, &ntr_card_spi_program);
|
||||
#endif
|
||||
pio_sm_config c = ntr_card_program_get_default_config(sProgramOffset);
|
||||
sm_config_set_out_pins(&c, PIN_D0, 8);
|
||||
sm_config_set_in_pins(&c, PIN_D0);
|
||||
sm_config_set_sideset_pins(&c, PIN_D5);
|
||||
sm_config_set_set_pins(&c, PIN_D0, 5);
|
||||
sm_config_set_out_shift(&c, true, true, 32);
|
||||
sm_config_set_in_shift(&c, false, true, 32);
|
||||
sm_config_set_clkdiv(&c, 1);
|
||||
pio_sm_set_pindirs_with_mask(pio0, 0, 0, PIN_INPUT_MASK);
|
||||
pio_sm_set_pins_with_mask(pio0, 0, 0, PIN_INPUT_MASK);
|
||||
pio0->input_sync_bypass = 0xFF000;
|
||||
pio_gpio_init(pio0, PIN_D0);
|
||||
pio_gpio_init(pio0, PIN_D1);
|
||||
pio_gpio_init(pio0, PIN_D2);
|
||||
pio_gpio_init(pio0, PIN_D3);
|
||||
pio_gpio_init(pio0, PIN_D4);
|
||||
pio_gpio_init(pio0, PIN_D5);
|
||||
pio_gpio_init(pio0, PIN_D6);
|
||||
pio_gpio_init(pio0, PIN_D7);
|
||||
|
||||
pio_sm_init(pio0, 0, sProgramOffset, &c);
|
||||
pio_set_irq0_source_enabled(pio0, pis_sm0_rx_fifo_not_empty, true);
|
||||
irq_set_exclusive_handler(PIO0_IRQ_0, ntrc_pioIrq);
|
||||
#ifdef DSPICO_ENABLE_WRFUXXED
|
||||
ntrc_initSpiUart(spiUartProgOffs);
|
||||
#endif
|
||||
|
||||
gpio_set_irq_callback(gpioIrq);
|
||||
gpio_set_irq_enabled(PIN_RST, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true);
|
||||
irq_set_enabled(IO_IRQ_BANK0, true);
|
||||
|
||||
irq_init_priorities();
|
||||
irq_set_priority(PIO0_IRQ_0, 0x40);
|
||||
irq_set_priority(IO_IRQ_BANK0, 0x40);
|
||||
irq_set_priority(USBCTRL_IRQ, 0x80);
|
||||
irq_set_priority(DMA_IRQ_1, 0x80);
|
||||
irq_set_priority(TIMER_IRQ_0, 0x80);
|
||||
|
||||
// printf("Starting\n");
|
||||
// printf("sProgramOffset %d\n", sProgramOffset);
|
||||
// printf("Boot time %d\n", (u32)bootTime);
|
||||
resetNtrCard();
|
||||
sIsSdCardMounted = false;
|
||||
initSd();
|
||||
|
||||
tryRebootToBootsel();
|
||||
|
||||
pwr_initPowerSaving();
|
||||
|
||||
while (1)
|
||||
{
|
||||
gSdCard.Update();
|
||||
gSdCard.Update();
|
||||
#ifdef ENABLE_R4_MODE
|
||||
ntrc_gameR4Update();
|
||||
#endif
|
||||
__wfi();
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user