tmc/src/eeprom.c

257 lines
6.3 KiB
C

#include "global.h"
#include "gba/eeprom.h"
#if defined(DEMO_USA) || defined(DEMO_JP)
const u8 unk[] = { 0xff, 0xff, 0xff, 0xff };
const u8 padding[0x18] = {};
#else
typedef struct EEPROMConfig {
u32 unk_00;
u16 size;
u16 waitcnt;
u8 address_width;
// u8 filler[3];
} EEPROMConfig;
const char EEPROM_V124[] = "EEPROM_V124";
extern const EEPROMConfig* gEEPROMConfig;
const EEPROMConfig gEEPROMConfig512 = { 0x200, 0x40, 0x300, 0x6 };
const EEPROMConfig gEEPROMConfig8k = { 0x2000, 0x400, 0x300, 0xe };
u16 EEPROMWrite(u16, const u16*, u8);
u16 EEPROMConfigure(u16 unk_1) {
u16 ret;
ret = 0;
if (unk_1 == 4) {
gEEPROMConfig = &gEEPROMConfig512;
} else {
if (unk_1 == 0x40) {
gEEPROMConfig = &gEEPROMConfig8k;
} else {
gEEPROMConfig = &gEEPROMConfig512;
ret = 1;
}
}
return ret;
}
static void DMA3Transfer(const void* src, void* dest, u16 count) {
u32 temp;
u16 IME_save;
IME_save = REG_IME;
REG_IME = 0; // disable all interrupts
temp = REG_WAITCNT & 0xf8ff;
temp |= gEEPROMConfig->waitcnt; // configure wait state 2
REG_WAITCNT = temp;
REG_DMA3SAD = (u32)src;
REG_DMA3DAD = (u32)dest;
REG_DMA3CNT = count | 0x80000000; // enable dma
while ((REG_DMA3CNT_H & 0x8000) != 0) {} // wait for dma to finish
REG_IME = IME_save;
}
/**
* reads 64 bit (8 byte) from eeprom
*
* @param address 6/14 bit depending on eeprom size
* @param data u16[4]
* @return errorcode, 0 on success
*/
u16 EEPROMRead(u16 address, u16* data) {
u16 buffer[0x44];
u16* ptr;
u8 t1, t2;
u16 value;
if (address >= gEEPROMConfig->size) {
return EEPROM_OUT_OF_RANGE;
} else {
ptr = buffer;
// setup address
(u8*)ptr += (gEEPROMConfig->address_width << 1) + 1;
((u8*)ptr)++;
for (t1 = 0; t1 < gEEPROMConfig->address_width; t1++) {
*(ptr--) = address;
address >>= 1;
}
// read request
*(ptr--) = 1;
*ptr = 1;
// send address to eeprom
DMA3Transfer(buffer, (u16*)0xd000000, gEEPROMConfig->address_width + 3);
// recieve data
DMA3Transfer((u16*)0xd000000, buffer, 0x44);
// 4 bit junk
ptr = buffer + 4;
data += 3;
// copy data into output buffer
for (t1 = 0; t1 < 4; t1++) {
value = 0;
for (t2 = 0; t2 < 0x10; t2++) {
value <<= 1;
value |= (*ptr++) & 1;
}
*(data--) = value;
}
return 0;
}
}
u16 EEPROMWrite1(u16 address, const u16* data) {
return EEPROMWrite(address, data, 1);
}
// reading from EEPROM like a status register
#define REG_EEPROM (*(u16*)0xd000000)
// this is the furthest I could get
// 0x080B16AC
NONMATCH("asm/non_matching/code_080B1520/EEPROMWrite.inc", u16 EEPROMWrite(u16 address, const u16* data, u8 unk_3)) {
u16 buffer[0x52]; // this is one too large?
vu16 stack_a4;
vu16 prev_vcount; // stack + a6
vu16 current_vcount; // stack + a6
vu32 passed_scanlines; // stack + ac
u32 r2;
u8 i, j;
u16* ptr;
if (address >= gEEPROMConfig->size)
return EEPROM_OUT_OF_RANGE;
ptr = buffer + gEEPROMConfig->address_width + 0x42;
*ptr = 0;
ptr--;
// copy data into buffer
for (i = 0; i <= 3; i++) {
r2 = *data;
data++;
for (j = 0; j <= 0xf; j++) {
*ptr = r2;
ptr--;
r2 = r2 >> 1;
}
}
// copy address to buffer
for (i = 0; i < gEEPROMConfig->address_width; i++) {
*ptr = address;
ptr--;
address = address >> 1;
}
*ptr = 0;
ptr--;
*ptr = 1;
DMA3Transfer(buffer, (u16*)0xd000000, gEEPROMConfig->address_width + 0x43);
stack_a4 = 0;
prev_vcount = REG_VCOUNT;
passed_scanlines = 0;
if (stack_a4 == 0) {
if ((REG_EEPROM & 1) != 0)
goto bad;
}
// before here its only regalloc, but after I cant get it to work
do {
do {
do {
current_vcount = REG_VCOUNT;
if (current_vcount != prev_vcount) {
if (current_vcount >= prev_vcount) {
passed_scanlines += current_vcount - prev_vcount;
} else {
passed_scanlines += (current_vcount + 0xe4) - prev_vcount;
}
if (passed_scanlines > 0x88) {
if (stack_a4 != 0)
return 0;
if ((REG_EEPROM & 1) != 0)
return 0;
return 0xc001;
}
prev_vcount = current_vcount;
}
} while (stack_a4 != 0);
} while ((REG_EEPROM & 1) != 0);
bad:
stack_a4++;
} while (unk_3 != 0);
return 0;
}
END_NONMATCH
u16 EEPROMCompare(u16 address, const u16* data) {
u16 ret;
u16 buffer[4];
u16* ptr;
u8 i;
ret = 0;
if (address >= gEEPROMConfig->size) {
return EEPROM_OUT_OF_RANGE;
}
EEPROMRead(address, buffer);
ptr = buffer;
for (i = 0; i < ARRAY_COUNT(buffer); i++) {
if (*data++ != *ptr++) {
ret = EEPROM_COMPARE_FAILED;
break;
}
}
return ret;
}
const char EEPROM_NOWAIT[] = "EEPROM_NOWAIT";
u16 EEPROMWrite1_check(u16 address, const u16* data) {
u8 i;
u16 ret;
for (i = 0; i < 3; i++) {
ret = EEPROMWrite1(address, data);
if (ret == 0) {
ret = EEPROMCompare(address, data);
if (ret == 0)
break;
}
}
return ret;
}
u16 EEPROMWrite0_8k(u16 address, const u16* data) {
u16 ret;
if (gEEPROMConfig->unk_00 != 0x200) {
ret = EEPROMWrite(address, data, 0);
} else {
ret = EEPROM_UNSUPPORTED_TYPE;
}
return ret;
}
u16 EEPROMWrite0_8k_Check(u16 address, const u16* data) {
u8 i;
u16 ret;
for (i = 0; i < 3; i++) {
ret = EEPROMWrite0_8k(address, data);
if (ret == 0) {
ret = EEPROMCompare(address, data);
if (ret == 0) {
break;
}
}
}
return ret;
}
const char thing[0x1c] = "\xff\xff\xff\xff";
#endif