EverDrive-64 v3: Difference between revisions

(describe more registers)
 
(16 intermediate revisions by the same user not shown)
Line 7:
RTC: supported
 
Save: 4k4ki/16k16ki bit EEPROM, 32KiB/128KiB SRAM, 128KiB Flash
 
USB Serial: 512-bytes block read-write
 
SD: SD or SDHC
 
== Registers ==
Line 33 ⟶ 35:
| 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
Line 39 ⟶ 41:
| 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 || HardwareFirmware version
|-
| 0x08040030 || ? || R/W || I2C to access RTC
Line 57 ⟶ 59:
| 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
Line 78 ⟶ 80:
! bit from lsb !! description
|-
| 15 || 1=startfinish 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)
| 6-5 || I2C/RTC??
|-
| 3 || WR_ADDR_MASK??
Line 103 ⟶ 105:
|-
|4
|1=SPI is busy (REG_SPI <-> SD is transferring)
|SPI?
|-
|3
Line 109 ⟶ 111:
|-
|2
|TXE# on USB FIFO (0=able to send some data to Host)
|-
|1
Line 143 ⟶ 145:
 
=== 0x08040010 (REG_MSG) ===
Read/Write
TBA
 
It seems generic 16bit storage.
 
In ED64 OS v2.12, this register used as following:
 
{| class="wikitable"
!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) ===
Line 181 ⟶ 198:
 
=== 0x0804001C (REG_SPI_CFG) ===
Read/Write only
{| class="wikitable"
!bit from lsb
Line 214 ⟶ 231:
 
=== 0x08040024 (REG_SAV_CFG) ===
Read/Write only
{| class="wikitable"
!bit from lsb
Line 220 ⟶ 237:
|-
|15
|1=enable ED64 save page
|always 1?
|-
|7
|1=enable game save page (have priority than ED64 page)
|unknown but 1?
|-
|3
Line 229 ⟶ 246:
|-
|2
|EEPROM size: 0=4kbit4kibit 1=16kbit16kibit
|-
|1
Line 242 ⟶ 259:
!description
|-
|0x0080
|0x8080
|Save is disabled
|-
|0x0082
|0x8082
|32KiB SRAM enabled
|-
|0x008A
|0x808A
|128KiB SRAM enabled
|-
|0x0081
|0x8081
|4kbit4kibit EEPROM enabled
|-
|0x0085
|0x8085
|16kbit16kibit EEPROM enabled
|-
|0x0088
|0x8088
|128KiB Flash enabled (!?)
|-
|0x800A
|128KiB ED64 save page enabled (mainly from 0x1E000)
|}
=== 0x08040028 (REG_SEC) ===
Write only?
TBA
 
=== 0x0804002C (REG_VER) ===
Line 270 ⟶ 290:
|-
|15-8
|HWFirmware major version
|-
|7-0
|HWFirmware minor version
|}
ex. 0x0304 for HWFirmware v3.04
 
=== 0x08040030 (I2C/RTC) ===
Line 294 ⟶ 314:
 
=== 0x08040040 (REG_CFG_CNT) ===
Read/Write on REG_CFG&1==0
TBA
{| class="wikitable"
!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
TBA
{| class="wikitable"
!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
{| class="wikitable"
!bit from lsb
Line 306 ⟶ 350:
|-
|14
|1?
|-
|13
Line 323 ⟶ 367:
|1=FPGA configured
|}
 
SDRAM must be disabled (REG_CFG & 1 must be zero).
=== 0x0804004C (REG_CRC) ===
Read only? on REG_CFG&1==0
{| class="wikitable"
!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 <code>REG_CFG &= ~1</code> (disable SDRAM)
* read from cart usually (by <code>*(uint32_t*)0xB0000000</code> etc, or use PI DMA)
 
{| class="wikitable"
!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.
{| class="wikitable"
|+Date in FAT Style
!bit from lsb
!description
|-
|15-9
|year - 1980
|-
|8-5
|month (start from 1)
|-
|4-0
|day (start from 1)
|}
 
== USB Serial Communication ==
Line 330 ⟶ 446:
=== Common Code ===
Before communication, you must enable ED64 registers.
 
TBA
<syntaxhighlight lang=c>
#include <stdint.h>
 
*(volatile uint32_t *)0xA8040000; /* dummy read */
*(volatile uint32_t *)0xA8040020 = 0x1234; /* enable ED64 registers */
</syntaxhighlight>
 
=== 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.
 
TBA
<syntaxhighlight lang=c>
/* 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 */
</syntaxhighlight>
 
=== Reading Data from the Host ===
You should use USB->Cart DMA on ED64 first, then transfer data from cart ROM area to RDRAM.
 
TBA
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.
 
<syntaxhighlight lang="c">
/* 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 */
</syntaxhighlight>
 
[[Category:Flash Carts]]
24

edits