Skip to content
Buu342 edited this page Nov 16, 2023 · 25 revisions

This page describes how the UNFLoader tool and USB library handles the 64Drive flash cart.

The 64Drive is a flashcart developed by marshallh and sold on his retroactive website. It features a very fast 8MB/s USB FTDI chip, and very extensive documentation (Denoted hereafter as "hardware specification" or "hardware spec"). The 64Drive's USB protocol only works if the cart is running firmware versions 2.05 and above. The 64Drive is available in two different hardware revisions, Hardware 1 and Hardware 2 (Denoted hereafter as "HW1" and "HW2" respectively)

On the 64Drive, 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 64Drive communication using the D2XX FTDI library.

⚠️ All data (both sent and received) on the 64Drive must be 4 byte aligned. There are some caveats to this which will be mentioned further on.

Differences between Hardware 1 and 2 revisions

HW1 runs in Asynchronous mode while HW2 runs in Synchronous mode. For USB communication, in theory HW2 features a mode called "Extended Address", which allows the 64Drive to support ROMs up to 256MB in size. This functionality does not actually work on the 64Drive, it was presumably going to be added in the next firmware update (which never happened).

Detecting a 64Drive (PC side)

After probing the connected devices, it is a matter of comparing the Description and ID values to see if they match up with any of the following:

Description (String) ID (DWORD)
HW1 64drive USB device A 0x4036010
HW2 64drive USB device 0x4036014

Detecting a 64Drive (N64 side)

Simply call usb_io_read, reading from the Hardware Magic value described in the Registers table on page 2 of the hardware spec. The connected device is a 64Drive if the returned value is equivalent to 0x55444556.

Opening the 64Drive's USB interface (PC side)

Open the deivce and set its timeouts to a large enough value (by default, 5000 milliseconds is used). If the HW2 is being detected, synchronous mode is set by setting the FT_BITMODE_RESET and FT_BITMODE_SYNC_FIFO bit modes with mask value of 0xFF. Finally, it is recommended to purge the receive and transmission buffers before continuing any further.

The 64Drive's USB protocol (PC side)

As explained in the hardware spec, the 64Drive uses a command based protocol for communication. Everything you need to know about the available commands are already explained there on pages 15 to 21.

Uploading a ROM via USB

To upload a ROM, the N64 must be turned off and the USB must be connected. The 64Drive does not set the CIC and save types by default, and therefore these must be sent with the 0x72 and 0x70 commands respectively (setting the CIC is not required for HW1, but it is for HW2). The 0x20 command is then used to upload the ROM itself, providing the ROM chunk size and the offset in SDRAM to store it in. After every command, the 64Drive will reply with 3 bytes containing CMP and the last byte with the command (so if you sent 0x20, you will receive CMP + 0x20).

⚠️ ROMS should be padded to the nearest 512 bytes before uploading, and then an extra 512 bytes should be appended to the end as a safety buffer. Failure to do so can result in the last 512 bytes of the ROM getting corrupted.

Checking if the device supports Debug Mode

The 64Drive has the 0x80 command, which gets the version of the firmware. Mask the received result with 0x0000FFFF. If the result is smaller than 205, then the device will not support debug mode.

⚠️ If a ROM is currently running on the cart, and it is actively outputting through USB, the CMP signal might get mixed in between incoming data, so you will need to filter it out.

N64 -> PC USB Communication

In order to send data to the connected PC, follow the instructions outlined in page 14 of the hardware specification document. For the Block Type value mentioned in Param1/Result1, simply use one of the DATATYPE values described in the previous chapter. The data sent by the 64Drive will be automatically formatted in the communication protocol used by UNFLoader (IE the 64Drive will send DMA@ followed by the data header for you, meaning you will not need to append this data manually into what you send through USB).

On the PC side, simply read the 4 bytes DMA header, 4 bytes with the data header, N bytes for the data, and then the CMPH signal.

PC -> N64 USB Communication

On page 13 of the hardware spec, the process for arming the USB FIFO to receive data from the PC is explained, and in page 14 it is shown how to disarm the USB FIFO. However the arming process described in the document is wrong. This, I believe, is due to a bug in the firmware, however I cannot confirm it as marshallh has been difficult to reach.

The hardware spec claims that you can arm the buffer with any size you want, so long as you repeatedly rearm the USB to service the rest of the incoming data. However, in practice, the 64Drive will lock up if the size of the data is larger than the armed buffer.

The hardware spec also states that the armed buffer can by any size smaller than 8MB, and while this is true, in practice any data that is larger than 512 bytes (which is the internal USB buffer's size) has a high chance to get mangled (bytes can go missing, swap places, etc...). This is because the 4 byte alignment is misleading. As soon as the data is larger than 512 bytes, you must align it to 512 bytes. Also, if the data is larger than 512 bytes, due to a 64Drive bug you must append an extra 512 bytes as a safety buffer, as the 64Drive will consistently miss the first 8 bytes it attempts to read from the last 512 byte chuck.

Another interesting point, but the arming size must be larger than zero, otherwise the 64Drive will hang.

⚠️ Something which isn't explained in the hardware specification (possibly due to a firmware bug) is that the 64Drive will eventually lock up when armed and left running. For UNFLoader's USB library, I decided to arm the 64Drive, check if data was received, and then disarm it right after. It is important to wait for the status registers during each one of these steps, as explained in the 64Drive hardware spec. Failure to do so can result in incoming data going missing.