EverDrive-64 v3
The EverDrive-64 v3 is a flash cart made by Krikzz.
Basic information
ROM: Max 64MiB
RTC: supported
Save: 4ki/16ki bit EEPROM, 32KiB/128KiB SRAM, 128KiB Flash
USB Serial: 512-bytes block read-write
SD: SD or SDHC
Registers
All registers must be accessed by 32bit word, but it seems only lower 16bits are valid.
High 16bits of all registers seems REG_STATUS on read.
Base PI address for registers is 0x08040000
(Cartridge Domain 2, SRAM area +0x40000)
You should access these registers from CPU through no-cached segment, i.e. +0xA0000000
, ex. 0xA8040020
for REG_KEY.
PI address | name | R/W | description |
---|---|---|---|
0x08040000 | REG_CFG | R/W | ED64 general configurations |
0x08040004 | REG_STATUS | R | ED64 registers, SPI, DMA statuses |
0x08040008 | REG_DMA_LEN | W | SD/USB DMA length in 512bytes blocks - 1 (ex. 0 = 0x200 bytes) |
0x0804000C | REG_DMA_RAM_ADDR | W | SD/USB Cart address in 2048bytes blocks (ex. 1 = 0x00000800) |
0x08040010 | REG_MSG | R/W | 16bit general storage? used to remember last used save type by ED64 OS (menu) |
0x08040014 | REG_DMA_CFG | W | Invoke SD/USB DMA |
0x08040018 | REG_SPI | R/W | SPI (SD card) DAT/CMD (write invoke CLK) |
0x0804001C | REG_SPI_CFG | R/W | SPI (SD card) configurations |
0x08040020 | REG_KEY | W | Enable or disable ED64 registers |
0x08040024 | REG_SAV_CFG | R/W | Save configurations (EEPROM/SRAM/FLASH) |
0x08040028 | REG_SEC | ? | ? |
0x0804002C | REG_VER | R | Firmware version |
0x08040030 | ? | R/W | I2C to access RTC |
0x08040034 | ? | ? | ? |
0x08040038 | ? | ? | ? |
0x0804003C | ? | ? | ? |
0x08040040 | REG_CFG_CNT | R/W | FPGA configuration control |
0x08040044 | REG_CFG_DAT | W | FPGA configuration data |
0x08040048 | MAX_MSG | R/W | Some configurations |
0x0804004C | REG_CRC | ? | ? |
0x08040050 | ? | ? | Flash? |
0x08040054 | ? | ? | Flash? |
0x08040000 (REG_CFG)
Read/Write
bit from lsb | description |
---|---|
15 | 1=finish FPGA configuration? (after REG_CFG_* writes) |
9-8 | D64 specific?? |
6-5 | RTC (00=disable, 01=RTC emulation enabled through Cart EEPROM command 06/07, 11=RTC access enabled via I2C) |
3 | WR_ADDR_MASK?? |
2 | WR_MOD?? |
1 | 1=16bit swap on SD DMA read |
0 | 1=enable SDRAM on cart (usually set to 1) |
0x08040004 (REG_STATUS)
Read only
bit from lsb | description |
---|---|
15 | 1=SDRAM enabled? |
4 | 1=SPI is busy (REG_SPI <-> SD is transferring) |
3 | RXF# on USB FIFO (0=some data from Host exists) |
2 | TXE# on USB FIFO (0=able to send some data to Host) |
1 | DMATOUT (1=last DMA was timed out, i.e. last transfer is less than 512bytes) |
0 | DMABUSY (1=DMA is ongoing) |
0x08040008 (REG_DMA_LEN)
Write only
bit from lsb | description |
---|---|
15-0 | Next SD/USB DMA transfer size in 512 bytes step, minus 1.
ex. 0 = 0x200 bytes, 1 = 0x400 bytes, 2 = 0x600 bytes... |
0x0804000C (REG_DMA_RAM_ADDR)
Write only
bit from lsb | description |
---|---|
15-0 | Next SD/DMA DMA transfer size in 2048 bytes step.
ex. 0 = 0x00000000, 1 = 0x00000800, 2 = 0x00001000... This is in ED64 ROM address space, ex. 0xB0000000 on CPU = 0x10000000 on PI = 0x00000000 on ED64 ROM. |
0x08040010 (REG_MSG)
Read/Write
It seems generic 16bit storage.
In ED64 OS v2.12, this register used as following:
bit from lsb | description |
---|---|
4 | last ROM is 64DD image |
3-0 | last ROM's savetype (0=none, 1=EEPROM 4kibit, ... same as /ED64/save_db.txt) |
0x08040014 (REG_DMA_CFG)
Write only
value | description |
---|---|
1 | SD -> Cart |
2 | Cart -> SD |
3 | USB -> Cart |
4 | Cart -> USB |
Note that above table numbers are value, not "bit from lsb".
You must set REG_DMA_LEN and REG_DMA_RAM_ADDR before writing this register.
0x08040018 (REG_SPI)
Read/Write
bit from lsb | description |
---|---|
7-0 | dat/cmd value. Bits are shifted in from lsb if 1bit mode. |
Writing value to this invokes clock CLK on SD card.
You should also write this to read. (write value is ignored)
0x0804001C (REG_SPI_CFG)
Read/Write
bit from lsb | description |
---|---|
5 | Bits transferred on writing REG_SPI: 0=8bits 1=1bit |
4 | Which line to R/W: 0=CMD 1=DAT |
3 | Read or write (on writing REG_SPI): 0=write 1=read |
2 | Slave Select line on SD card |
1-0 | CLK speed: 10=init 01=25MHz 00=50MHz |
0x08040020 (REG_KEY)
Write only
bit from lsb | description |
---|---|
15-0 | Enable or disable ED64 registers: 0=disable, 0x1234=enable |
Note that you should dummy-read REG_CFG before writing to REG_KEY, or it may be ignored (glitch).
0x08040024 (REG_SAV_CFG)
Read/Write
bit from lsb | description |
---|---|
15 | 1=enable ED64 save page |
7 | 1=enable game save page (have priority than ED64 page) |
3 | SRAM size: 0=32KiB 1=128KiB |
2 | EEPROM size: 0=4kibit 1=16kibit |
1 | SRAM ON: 1=SRAM |
0 | EEPROM ON: 1=EEPROM |
But this register should be treated as a value not bitfields (like REG_DMA_CFG)
value | description |
---|---|
0x0080 | Save is disabled |
0x0082 | 32KiB SRAM enabled |
0x008A | 128KiB SRAM enabled |
0x0081 | 4kibit EEPROM enabled |
0x0085 | 16kibit EEPROM enabled |
0x0088 | 128KiB Flash enabled (!?) |
0x800A | 128KiB ED64 save page enabled (mainly from 0x1E000) |
0x08040028 (REG_SEC)
Write only?
0x0804002C (REG_VER)
Read only
bit from lsb | description |
---|---|
15-8 | Firmware major version |
7-0 | Firmware minor version |
ex. 0x0304 for Firmware v3.04
0x08040030 (I2C/RTC)
Read/Write
bit from lsb | description |
---|---|
2 | CLK |
0 | DAT |
You must set DAT=1 before read, or you'll get always DAT=0 (because of I2C's open-drain).
DS1337 (RTC) at address 0x58.
0x08040040 (REG_CFG_CNT)
Read/Write on REG_CFG&1==0
bit from lsb | description |
---|---|
3 | 1=REG_CFG_DAT is transferring [R] |
2 | 1=FPGA is configuring? [R] |
0 | 0=unconfigure FPGA? [W] |
SDRAM must be disabled (REG_CFG & 1 must be zero).
0x08040044 (REG_CFG_DAT)
Write only? on REG_CFG&1==0
bit from lsb | description |
---|---|
15-0 | configuration data (part of bitstream) |
SDRAM must be disabled (REG_CFG & 1 must be zero).
0x08040048 (REG_MAX_MSG)
Read/Write on REG_CFG&1==0
bit from lsb | description |
---|---|
14 | 1? |
13 | 1=SDHC |
12 | 1=SD card initialized |
11-10 | tvtype (value that IPL3 sets) |
9 | 1=tvtype in REG_MAX_MSG is set |
8 | 1=FPGA configured |
SDRAM must be disabled (REG_CFG & 1 must be zero).
0x0804004C (REG_CRC)
Read only? on REG_CFG&1==0
bit from lsb | description |
---|---|
15-12 | HW major version? |
11-0 | ? |
SDRAM must be disabled (REG_CFG & 1 must be zero).
This register seems not related to "Cyclic Redundancy Check".
0x08040050
Write only? on REG_CFG&1==0
TBA
SDRAM must be disabled (REG_CFG & 1 must be zero).
0x08040054
Write only on REG_CFG&1==0 ?
TBA
SDRAM must be disabled (REG_CFG & 1 must be zero).
ED64 Boot ROM Header
You can read boot ROM header by:
- set
REG_CFG &= ~1
(disable SDRAM) - read from cart usually (by
*(uint32_t*)0xB0000000
etc, or use PI DMA)
PI address | bytes | description |
---|---|---|
0x10000020 | 12 | "ED64 SD boot", can be used to identify SD is usable or not (=SPI) |
0x10000038 | 2 | assembly date in FAT style |
0x1000003A | 2 | assembly time in 2-seconds from 00:00:00, ex. 0x5878 for 12:34:56 |
0x1000003C | 2 | serial number (16bit binary, hex) |
They are, of course, big endian.
bit from lsb | description |
---|---|
15-9 | year - 1980 |
8-5 | month (start from 1) |
4-0 | day (start from 1) |
USB Serial Communication
Common Code
Before communication, you must enable ED64 registers.
#include <stdint.h>
*(volatile uint32_t *)0xA8040000; /* dummy read */
*(volatile uint32_t *)0xA8040020 = 0x1234; /* enable ED64 registers */
Sending Data to the Host
You should transfer data from RDRAM to some area on cart "ROM" area first, then use Cart->USB DMA on ED64.
/* polling style */
void rdram_to_host(
void *src, /* pointer for data aligned by 64 bits (8 bytes) */
uint32_t tmp_cart_addr, /* somewhere aligned by 2048 bytes */
uint32_t len /* length aligned 512 bytes */
) {
uintptr_t i;
/* flush D-cache (primary data hit writeback invalidate; 16 bytes per D-cache-line on N64) */
for(i = (uintptr_t)src & ~15; i < (uintptr_t)src + (uintptr_t)len; i += 16) {
__asm volatile("cache 0x15, %0" :: "m"(*(uint32_t*)i));
}
*(volatile uint32_t *)0xA4600010 = 3; /* reset PI and clear interrupt */
/* transfer (PI DMA) RDRAM to Cart */
*(volatile uint32_t *)0xA4600000 = (uint32_t)src & 0x00FFffff; /* XXX: assuming src points to kseg0 or kseg1 */
*(volatile uint32_t *)0xA4600004 = tmp_cart_addr;
*(volatile uint32_t *)0xA4600008 = len - 1;
while(*(volatile uint32_t *)0xA4600010 & 1) /* busyloop */ ; /* wait for PI DMA done */
/* Cart->USB DMA on ED64 */
while(*(volatile uint32_t *)0xA8040004 & 4) /* busyloop */ ; /* wait until REG_STATUS & TXE# becomes zero = able to tx */
*(volatile uint32_t *)0xA8040008 = len / 512 - 1; /* set REG_DMA_LEN */
*(volatile uint32_t *)0xA8040000; /* dummy read for previous PI write is done (REG_CFG is just because) */
*(volatile uint32_t *)0xA804000C = tmp_cart_addr / 2048; /* set REG_DMA_ADDR */
*(volatile uint32_t *)0xA8040000; /* dummy read for previous PI write is done (REG_CFG is just because) */
*(volatile uint32_t *)0xA8040014 = 4; /* set REG_DMA_CFG to Cart->USB invokes DMA */
while(*(volatile uint32_t *)0xA8040004 & 1) /* busyloop */ ; /* wait for Cart->USB DMA done */
}
...
uint8_t __attribute((aligned(8))) buffer[512];
/* ... some modification to "buffer" */
rdram_to_host(buffer, 0x00400000 - 2048, 512); /* using last ROM area for communication */
Reading Data from the Host
You should use USB->Cart DMA on ED64 first, then transfer data from cart ROM area to RDRAM.
At least on HW v3.04, it seems that USB->Cart transfer is done at 16-bit halfwords. If received data is NOT aligned at 16-bit, that last byte will be lost. Of course if received data is shorter than "len", DMA will be timed out, cause waiting ~500ms to DMA done until timeout, so you should send data from host by 512 bytes block for faster communication.
/* polling style */
int host_to_rdram(
void *dst, /* pointer for data aligned by 64 bits (8 bytes) */
uint32_t tmp_cart_addr, /* somewhere aligned by 2048 bytes */
uint32_t len /* length aligned 512 bytes */
) {
uintptr_t i;
/* REG_STATUS & RXF# is zero = data is arriving, not zero = not arrived */
if(*(volatile uint32_t *)0xA8040004 & 8) {
/* no data is arrived now */
return 0;
}
/* invalidate D-cache (primary data hit invalidate; 16 bytes per D-cache-line on N64) */
for(i = (uintptr_t)dst & ~15; i < (uintptr_t)dst + (uintptr_t)len; i += 16) {
__asm volatile("cache 0x11, %0" :: "m"(*(uint32_t*)i));
}
*(volatile uint32_t *)0xA4600010 = 3; /* reset PI and clear interrupt */
/* USB->Cart DMA on ED64 */
*(volatile uint32_t *)0xA8040008 = len / 512 - 1; /* set REG_DMA_LEN */
*(volatile uint32_t *)0xA8040000; /* dummy read for previous PI write is done (REG_CFG is just because) */
*(volatile uint32_t *)0xA804000C = tmp_cart_addr / 2048; /* set REG_DMA_ADDR */
*(volatile uint32_t *)0xA8040000; /* dummy read for previous PI write is done (REG_CFG is just because) */
*(volatile uint32_t *)0xA8040014 = 3; /* set REG_DMA_CFG to USB->Cart invokes DMA */
while(*(volatile uint32_t *)0xA8040004 & 1) /* busyloop */ ; /* wait for USB->Cart DMA done */
if(*(volatile uint32_t *)0xA8040004 & 2) {
/* last DMA timed out... you may be treat this as error (or you can read partially transferred data, comment out next return) */
return -1;
}
/* transfer (PI DMA) Cart to RDRAM */
*(volatile uint32_t *)0xA4600000 = (uint32_t)dst & 0x00FFffff; /* XXX: assuming dst points to kseg0 or kseg1 */
*(volatile uint32_t *)0xA4600004 = tmp_cart_addr;
*(volatile uint32_t *)0xA460000C = len - 1;
while(*(volatile uint32_t *)0xA4600010 & 1) /* busyloop */ ; /* wait for PI DMA done */
/* success */
return 1;
}
...
uint8_t __attribute((aligned(8))) buffer[512];
int result;
result = host_to_rdram(buffer, 0x00400000 - 2048, 512); /* using last ROM area for communication */
/* "buffer" is modified if 0 < result */