NDS自制软件教程5



掌叔
2008-06-15 09:34:02

摘自:ndsbbs
作者:nashi1987

这几篇都是翻译国外的教程,按顺序翻译下来的。GBA卡SRAM读写一般似乎没多大用处,但还是了解以下为好。

GBA卡有一个用来存档用的SRAM芯片,其中的数据可以在断电后依然保存。这一部分在NDS中依然可以读写

。这样就允许DS自制软件在这里储存数据。

这一部分的教程介绍如何读写SRAM。

GBA卡内存布局
NDS中GBA ROM 定位于内存0x08000000处,SRAM在0x0A000000. SRAM大小为64KB。

GBA卡的内存必须被影射到一个确定的处理器,在同一时间只有ARM7或ARM9中的一个可以访问这段内存。

我们使用WAIT_CR寄存器控制当前哪一个处理器使用这段内存。

当允许ARM7访问GBA内存时,寄存器第7位置位,当ARM9访问时,7位清零。

这是实现此功能的代码示例:


/* Hold a local copy of some card data */
static char card_id[5];

/* 第7位清零使ARM9可访问GBA内存
WAIT_CR &= ~0x80;

/*现在可以读写GBA内存了 */
memcpy(card_id, (char*)0x080000AC, 4);



GBA卡ID

Darkain在 GBADEV forum 中提到如果自制软件在向SRAM写数据时不先判断所插入是什麽卡会导致一些问

题。如果自制程序通过WIFI下载到NDS中,此时也许插槽中没有卡,也许有一个包含重要游戏存档的商业

卡,这时,自制程序不应该在未经允许的情况下擦除SRAM数据。

为避免这种情况发生我们应当检测卡的内存中的一个标记看是否包含‘PASS’。这个代码包含在所有目前

的自制软件中并且涉及到PASSME的早期版本的自制软件运行方法。检测方法很简单并且我建议在读写前检

测SRAM。

当卡带内存被映射后我们就可以读取这个标记了。在地址0x080000AC处包含一个 4 bytes的标记数据。以

下代码完成从此地址拷贝数据到一个本地变量:


static char card_id[5] = { 0,0,0,0,0 };

static void memcpy(char* dest, char const* src, int size) {
while(size--)
*dest++ = *src++;
}

void main() {
[...]

/* Copy contents of the 4 character ROM identifier into a local
variable. This should be 'PASS' for all homebrew ROM's. The
identifier is located at 0x080000AC.*/
memcpy(card_id, (char*)0x080000AC, 4);

[...]
}


检测‘PASS’代码是否存在我用这样一个函数,is_homebrew_cartridge:


/* Return true if the card id is 'PASS' */
static int is_homebrew_cartridge() {
return
card_id[0] == 'P' &&
card_id[1] == 'A' &&
card_id[2] == 'S' &&
card_id[3] == 'S';
}

void some_func() {
if(is_homebrew_cartridge()) {
write_to_sram();
}
}



读写SRAM:

映射后,SRAM被定位在内存地址0x0A000000,LIBNDS有一个指向这里的宏:SRAM:


#define SRAM ((uint8*)0x0A000000)


之所以这个宏是一个8位的,是因为所有对SRAM的读写必须每次8比特。16 bit 或 32 bit是无用的。这就

是为什麽之前的函数memcpy每次只拷贝1字节数据。

向这部分区域写的数据可以是各种格式的。你可以储存TXT文本,二进制数据等等。 在内存的开始处标记

数据结构可方便其他程序的读取。
在这篇教程中我们只读写以0终止的strings数据。当按下‘A’键时字符串被从SRAM读取并存储到本地变

量,sram_data,显示到屏幕上。


int keys = ~REG_KEYINPUT;
if(keys & KEY_A) {
/* Copy from SRAM to our local variable to display */
memcpy(sram_data, (char*)SRAM, sizeof(sram_data) - 1);
}


当‘B’键按下时将从本地静态变量中拷贝一个字符串到SRAM中储存:


if(keys & KEY_B) {
/* Copy a string of text to SRAM if the cartridge has a homebrew
ROM in it. */
const char text[] = "Hello from SRAM!";
const char error[] = "Not Homebrew! Copy failed.";
const char success[] = "Copy succeeded.";
if(is_homebrew_cartridge()) {
memcpy((char*)SRAM, text, sizeof(text));
memcpy(copy_status, success, sizeof(success));
}
else
memcpy(copy_status, error, sizeof(error));
}


以上就是SRAM的读写方法。

原文翻译,如有疏漏错误之处,还望大家多多指正!