Files
dspico-firmware/docs/commands.md
2025-11-23 17:03:31 +01:00

16 KiB

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.

Command Name Description
00 xx xx xP PP xx xx xx NTR_CMD_ID_NORMAL_READ_PAGE Reads a rom header page (512 bytes).
PPP must be a multiple of 512.
3C xx xx xx xx xx xx xx NTR_CMD_ID_NORMAL_CHANGE_MODE_NTR Switches to NTR secure mode.
3D xx xx xx xx xx xx xx NTR_CMD_ID_NORMAL_CHANGE_MODE_TWL Switches to TWL secure mode.
71 xx xx xx xx xx xx xx NTR_CMD_ID_NORMAL_3DS_DETECT Ignored, but used for console type detection.
90 xx xx xx xx xx xx xx NTR_CMD_ID_NORMAL_READ_ID Reads the card id (4 bytes).
9F xx xx xx xx xx xx xx NTR_CMD_ID_NORMAL_LOAD_TABLE Ignored, but used for console type detection.

Secure mode

In secure mode the received commands are blowfish encrypted.

NTR location TWL location
P table 0x1600 twlArea + 0x600
S boxes 0x1C00 twlArea + 0xC00
Secure area 0x4000 to 0x8000 twlArea + 0x3000 to twlArea + 0x7000

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.

Command Name Description
1x xx xx xx xx xx xx xx NTR_CMD_ID_SECURE_READ_ID Reads the card id (4 bytes).
2S SS Sx xx xx xx xx xx NTR_CMD_ID_SECURE_READ_SEGMENT Reads a 4 KB secure segment.
Segment number SSS must be 4, 5, 6 or 7.
The command needs to be issued 9 times to get the entire segment.
The first time, the command is decrypted and no data is returned.
The next 8 times 512 bytes are returned.
4x xx xM MM NN Nx xx xx NTR_CMD_ID_SECURE_SCRAMBLER_ON Enables the scrambler. MMMNNN is used to seed the scrambler.
Ax xx xx xx xx xx xx xx NTR_CMD_ID_SECURE_CHANGE_MODE Switches to game mode.

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.

Command Name Description
B7 PP PP PP PP xx xx xx NTR_CMD_ID_GAME_READ_PAGE Reads a rom page (512 bytes).
PPPPPPPP must be a multiple of 512.
B8 xx xx xx xx xx xx xx NTR_CMD_ID_GAME_READ_ID Reads the card id (4 bytes).
FC xx xx xx xx xx xx xx NTR_CMD_ID_GAME_DISABLE_SCRAMBLING Switches to unscrambled game mode.

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.

Command Name Description
B7 PP PP PP PP xx xx xx NTR_CMD_ID_GAME_READ_PAGE Returns 512 bytes of garbage unless the ENABLE_R4_MODE define is used (see below).
B8 xx xx xx xx xx xx xx NTR_CMD_ID_GAME_READ_ID Reads the card id (4 bytes).
E3 xx xx xx SS SS SS SS NTR_CMD_ID_GAME_REQ_SD_READ Requests an SD read of sector SSSSSSSS.
E4 xx xx xx xx xx xx xx NTR_CMD_ID_GAME_GET_SD_STAT Returns 1 when the current SD operation (read or write) is complete,
or 0 otherwise. (4 bytes)
E5 xx xx xx xx xx xx xx NTR_CMD_ID_GAME_GET_SD_DATA Returns 512 bytes of SD data that was read previously.
E8 SS xx xx xx xx xx xx NTR_CMD_ID_GAME_USB_COMMAND Performs a USB command. This command has no payload data.
See below for the list of sub commands (SS).
E9 xI PP xT LL LL LL LL NTR_CMD_ID_GAME_USB_WRITE_DATA Writes 512 bytes of data to an endpoint buffer.
PP is the endpoint id. I specifies the buffer index (0 or 1).
T specifies whether a transfer should be started (1) or not (0).
LLLLLLLL specifies the actual data length (0 <= length <= 512).
Length zero is special cased to expect no payload data, for zero length transfers.
EA xx PP xI xx xx xx xx NTR_CMD_ID_GAME_USB_READ_DATA Reads 512 bytes of data from an endpoint buffer.
PP is the endpoint id. I specifies the buffer index (0 or 1).
EB xx xx xx xx xx xx xx NTR_CMD_ID_GAME_USB_GET_EVENT Dequeues an event from the USB event queue and returns it (4 bytes).
F6 E1 0D 9Q SS SS SS SS NTR_CMD_ID_GAME_WRITE_SD_DATA Writes 512 bytes of SD sector data. Q is 10XY (binary) with
X the WRITE_SD_DATA_IS_FIRST_FLAG indicating the start of a sequential write, and
Y the WRITE_SD_DATA_IS_LAST_FLAG indicating the last sector of a sequential write.

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.

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.

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.

Command Name Description
E8 01 xx xx xx xx xx xx USB_SUB_COMMAND_INIT Initializes USB.
E8 02 xx xx xx xx xx xx USB_SUB_COMMAND_BEGIN_SET_ADDRESS dcd_set_address(0, 0)
E8 03 xx xx xx xx xx xx USB_SUB_COMMAND_REMOTE_WAKEUP dcd_remote_wakeup(0)
E8 04 xx xx xx xx xx xx USB_SUB_COMMAND_CONNECT dcd_connect(0)
E8 05 xx xx xx xx xx xx USB_SUB_COMMAND_DISCONNECT dcd_disconnect(0)
E8 06 xx xx xx xx xx xx USB_SUB_COMMAND_SOF_ENABLE dcd_sof_enable(0, true)
E8 07 xx xx xx xx xx xx USB_SUB_COMMAND_SOF_DISABLE dcd_sof_enable(0, false)
E8 08 xx xx xx xx xx xx USB_SUB_COMMAND_EP_CLOSE_ALL dcd_edpt_close_all(0)
E8 09 PP xx xx xx xx xx USB_SUB_COMMAND_EP_STALL dcd_edpt_stall(0, PP)
E8 0A PP xx xx xx xx xx USB_SUB_COMMAND_EP_CLEAR_STALL dcd_edpt_clear_stall(0, PP)
E8 0B xx xx xx xx xx xx USB_SUB_COMMAND_EP_CLOSE dcd_edpt_close(0, PP)
E8 0C RR xx xx xx xx xx USB_SUB_COMMAND_FINISH_SET_ADDRESS usb_hw->dev_addr_ctrl = RR
E8 0D PP xT xx xx xS SS USB_SUB_COMMAND_EP_OPEN Opens endpoint PP. The endpoint will have type T
(0 = control, 1 = isochronous, 2 = bulk, 3 = interrupt)
and maximum packet size SSS.
E8 0E xx xx xx xx xx xx USB_SUB_COMMAND_CLEAR_EVENT_QUEUE Clears the USB event queue.
E8 0F xx xx xx xx xx xx USB_SUB_COMMAND_DEINIT Deinitializes USB.
E8 10 PP xI LL LL LL LL USB_SUB_COMMAND_BEGIN_TRANSFER Starts a transfer on endpoint PP. I is the buffer index (0 or 1),
and LLLLLLLL is the length (0 <= length <= 512).
E8 11 xx xx xx xx xx xx USB_SUB_COMMAND_INTERRUPT_ENABLE dcd_int_enable(0)
E8 12 xx xx xx xx xx xx USB_SUB_COMMAND_INTERRUPT_DISABLE dcd_int_disable(0)

R4 emulation

The following commands are additionally supported for R4 emulation when the ENABLE_R4_MODE define is used. See also r4.md.

Command Name Description
00 00 00 00 xx xx xx xx - Returns zero (4 bytes).
B0 xx xx xx xx xx xx xx - Get R4 card info. Returns 0x1F4 (4 bytes).
B2 PP PP PP PP xx xx xx - Starts a save read at address PPPPPPPP. 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).
B3 xx xx xx xx xx xx xx - Returns the 512 bytes of save data that were previously requested with command B2.
B4 PP PP PP PP xx xx xx - Initializes the cluster map for a rom (lsb of address is 0) or save file (lsb of address is 1). PPPPPPPP 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,
and 0 once complete (4 bytes).
B6 PP PP PP PP xx xx xx - Starts a rom read at address PPPPPPPP. 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).
B7 PP PP PP PP xx xx xx NTR_CMD_ID_GAME_READ_PAGE Returns the 512 bytes of rom data that were previously requested with command B6. PPPPPPPP is the 512 byte aligned rom address.
B9 PP PP PP PP xx xx xx - Starts an SD read at SD address PPPPPPPP. 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).
BA xx xx xx xx xx xx xx - Returns the 512 bytes of SD data that were previously requested with command B9.
BB PP PP PP PP xx xx xx - Starts an SD write to SD address PPPPPPPP. The address must be 512 byte aligned. The command expects 512 bytes of data to write.
BE xx xx xx xx xx xx xx - Gets the status of the SD write that was started previously with command BB. The command returns 1 while the card is busy writing, and 0 once the write is complete (4 bytes).