-
Notifications
You must be signed in to change notification settings - Fork 34
5) The SC64
This page describes how the UNFLoader tool and USB library handles the SC64 flashcart.
The SC64 (previously known as SummerCart64) is a free and open source N64 flashcart created by Polprzewodnikowy, fully available on his GitHub repo. It features a very fast 480Mb/s USB FTDI chip, and works similarly to the 64Drive. Besides the source code for the hardware, firmware, and the sc64deployer PC app, your only other source for the USB protocol is this very repository (UNFLoader, that is), as the cart's developer wrote support for it himself.
On the SC64, reads from cartridge space are mapped to SDRAM, meaning that you can use the usb_io_read and usb_io_write functions to address the different cartridge interface devices.
UNFLoader implemented SC64 communication using the D2XX FTDI library.
ℹ️ The SC64 has no byte alignment requirements.
After probing the connected devices, check if the device description matches "SC64" and the ID matches 0x04036014. If those two match, then the device is probably a SC64. To be sure, you need to open device and send IDENTIFIER_GET command to get response.
To detect flashcart presence you need to unlock register access first. Refer to the usb_findcart() function in usb.c for correct order and values for unlocking process. After successful unlocking you can read IDENTIFIER register located at address 0x1FFF000C that should return value 0x53437632 ("SCv2" in ASCII encoding).
The SC64's USB protocol is documented in usb.c. Commands are always 12 bytes big and start with C M and D, followed by a character that represents the command you want to send. The next 8 bytes are reserved for arguments. Some commands require you to write more than 8 bytes of arguments, so you should do so after sending the command header. Some commands send an 8 byte reply, which will contain the 3 bytes CMP, ERR, or PKT, and the fourth byte with the command you replied with. The last 4 bytes contain the size of the incoming reply, which you should read from USB and handle accordingly.
Open the device and set its timeouts to a large enough value (by default, 5000 milliseconds is used). Set the cart's latency timer to 0 and reset the bitmode to 0xFF. Finally, it is recommended to purge the receive and transmission buffers before continuing. If you send the identifier command ('v'), and the device replies back with SCv2, then you know you are dealing with a firmware 2 cart (which is required). However, if the version command ('V') returns a value not equal to 2 in the first 2 bytes of the reply, or smaller than 14 in the last 2 bytes of the reply, then you should halt as the firmware version is unsupported.
The USB upload process is done with the system turned off. You should start by putting the SC64 in reset state with the 'R' command.
Afterwards you must call the config command ('C') with the first argument 5 (for boot mode config) and the second argument with either 3 (if a CIC is to be set), or 1 (if not). If the CIC is to be set, then afterwards you call the CIC command ('B') with the following argument structure:
arg1: [31:25] unused
[24] disable CIC
[23:16] CIC seed
[15:0] IPL3 checksum (upper 16 bits)
arg2: [31:0] IPL3 checksum (lower 32 bits)
Setting the save type is just a matter of sending config command (C) with the first argument 6 (set save type) and the second argument with the savetype index.
You can now start uploading the ROM with the write command ('M'), first argument being the offset, and the second argument being the size of the incoming chunk. You call this multiple times in a loop until the ROM is uploaded in its entirety.
To finalize, if your ROM required SRAM saving, then you must send the config command (C) with 2 as the first argument (To enable shadow memory) and 1 as the second. Afterwards, send the flash wait command (p) with 0 and 0, and receive the 4 byte response which tells you the erase block size. Once received, in a loop send the erase block command (P) with the offset as the first argument and 0 as the second, followed by the write command to upload the given block of ROM. Finish by sending the wait command once more.
Similarly, if your ROM is larger than 64MB, you must enable extended address mode with the config command (C), using 14 as the first argument (to enable extended address mode) and 1 as the second. Afterwards, you perform all the steps you would've done after sending the config command (C). This must be done in this order because the memory space is not contiguous (you can enable shadow/extend address before uploading the ROM, but way might be more legible).
In order to send data to the connected PC, check out UNFLoader USB Library's usb.c, specifically, the usb_sc64_write function.
As outlined previously, the SC64 has its own USB protocol, so it is your duty to then format the data in a way that UNFLoader can handle. The SC64's implementation does not use the DMA@ or CMPH part of the protocol, opting only for the UNFLoader data header.
In order to write data to USB on the PC, check out the device_senddata_sc64 function in UNFLoader's device_sc64.cpp. The SC64 does not have a standard USB communication protocol, therefore, it is up to you to format the data in a way that UNFLoader can handle. The SC64's implementation does not use the DMA@ or CMPH part of the protocol, opting only for the UNFLoader data header.
In order to read the USB buffer on the N64, you can check out UNFLoader USB Library's usb.c usb_sc64_poll and usb_sc64_read function.