[FC][SRAM扩容教程(Mapper 4为例)]

来源:互联网 发布:通信网络优化是什么 编辑:程序博客网 时间:2024/06/05 19:55

[FC][SRAM扩容教程(Mapper 4为例)]

 

时间:2017.4.28

作者:FlameCyclone

工具:FCEUX 2.2.3,Hxd 1.7.7.0,6502_Simulator

ROM:双截龙2(J).nes

适用:没有使用SRAM的ROM

 

首先用Hxd打开ROM

 

然后扩容:

 

 

先看看任天堂产品系统文件对NES文件的说明:

NES文件格式

.NES文件为模拟用来储存NES卡带的映像。下面是一个.NES文件的结构。 

偏移

字节数

内容

03

4

字符串“NES^Z”用来识别.NES文件

4

1

16kB ROM的数目

5

1

8kB VROM的数目

6

1

D01=垂直镜像,0=水平镜像

D11=有电池记忆,SRAM地址$6000-$7FFF

D21=在$7000-$71FF有一个512字节的trainer

D314屏幕VRAM布局

D4D7ROM Mapper的低4

7

1

D0D3:保留,必须是0(准备作为副Mapper^_^

D4D7ROM Mapper的高4

8F

8

保留,必须是0

16-

16KxM

ROM段升序排列,如果存在trainer,它的512字节摆在ROM段之前

-EOF

8KxN

VROM,升序排列

 

然后知道这个ROM0x08PROM0x10VROM

接下来扩展PROM0x10个:

先把第0x04字节改为0x100x06字节的D1位置1(设置有SRAM):

 

由于mapper4ROM在模拟器载入时会把最后16KB载入到整个64KB内存的C000-FFFF,因此需要在最后的16KB PROM0x4000)前添加8x16KB PROM0x20000大小),然后跳转到最后一个PROM的头部:偏移计算:

最后一个PROM的头部= (总PROM- 1x 0x4000 + 文件头0x10字节。

于是可以得到双截龙2的是:

8-1x 0x4000 + 0x10 = 0x$1C010

然后跳转到$1C010

 

 

 

然后插入0x20000字节的0xFF

 

 

 

然后保存:

 

 

FCEUX打开正常运行:

 

查看文件信息:

 

 

 

接下来切页:

先打开十六进制编辑器:

 

 

中断地址

中断

优先权

$FFFA

NMI

$FFFC

RESET

$FFFE

IRQ/BRK

把滑块拉到最后,看看RESET重启中断:

 

 

RESET中断是ROM载入模拟器后最先开始运行的地方,只运行一次。

由此可知双截龙2RESET中断$FF65

接下来添加$FF65的执行断点:

打开调试器:

 

添加$FF65的执行断点:

 

 

 

 

单击确定:

 

 

然后重启ROM

 

调试器此时弹出来:

 

然后打开Hxd,写一段mapper 4的切换bank的程序:

先看看mapper 4的说明文档:

Mapper 4

 

$8000:  模式号

D0-D2:

0:选择2KBVROM存储体映射到PPU$0000

1:选择2KBVROM存储体映射到PPU$0800

2:选择1KBVROM存储体映射到PPU$1000

3:选择1KBVROM存储体映射到PPU$1400

4:选择1KBVROM存储体映射到PPU$1800

5:选择1KBVROM存储体映射到PPU$1C00

6:选择8KBROM存储体映射到$8000

7:选择8KBROM存储体映射到$A000

D6:

0:允许擦写$8000$A000

1:允许擦写$A000$C000

D7:

0:模式号D0-D2使用普通地址

1:模式号D0-D2地址异或$1000

 

$8001:  模式页面号

写入一个数(00-07),切换存储体到对应地址

 

$A000:  镜像选择

0:垂直镜像

1:水平镜像

 

$A001:  SaveRAM 切换

0:禁用$6000-$7FFF

1:启用$6000-$7FFF

 

$C000:  IRQ计数器

IRQ计数器的值存储在此处

 

$C001:  IRQ暂存器

IRQ暂存器的值存储在此处

 

$E000:  IRQ控制计数器0

向这里写入任何数来关闭IRQ,并从暂存器中拷贝数据开始计数,进入IRQ

 

$E001:  IRQ控制计数器1

向这里写入任何数,允许IRQ(退出IRQ,允许下一个IRQ进来)

 

那么就写段切页到$8000-$9FFF,然后跳转到$8000的切bank程序:

48 A9 06 8D 00 80 A9 0E 8D 01 80 20 00 80 68

PHA      累加器A入栈

LDA #$06    设置切bank地址为$8000-$9FFF

STA $8000

LDA #$0E    将第0x0Ebank切到$8000-$9FFF

STA $8001

JSR $8000    跳转到子程序$8000

PLA     累加器A出栈

 

为何切换的bank号是0x0E呢?

因为在扩容ROM后,文件PROM结构为:

原来的0x0716KB PROM +自己的0x0816KB PROM + 原来的最后0x0116KB PROM

 

Mapper 4bank一次是切8KB,那么文件结构就是:

原来的0x0E8KB PROM (00-0D) +自己的0x108KB PROM (0E-1D) +原来的最后0x018KB PROM (1E-1F)

因此选择扩容的第一个空白bank就是0x0Ebank

 

 

然后去调试器找RESET中断中可以放下切页程序的地方:

首先长度要小于等于自己写的切页程序。

可以看到$FF7C可以使用(一般找程序中已经禁用中断后的地方,也就是找使用了SEI指令后的地方)

 

然后跳转到$FF7C

 

 

 

复制下可以被替换用于写切页的程序:

先选中,再复制:

 

 

Hxd中新建一个文件,把复制的数据粘贴上去:

 

 

 

 

然后回到十六进制模拟器:

转到$FF7C对应的ROM地址:

 

 

然后复制Hxd的切页程序,粘贴到这里:

 

 

 

没有覆盖的用EA覆盖:

 

打开调试器可以看到变化:

 

然后添加$FF7C执行断点:

 

 

 

 

单击运行:

然后程序在$FF7C这里停下来了。

 

然后单击单步进入慢慢跟踪,直到跳转到$8000:

 

然后打开6502_Simulator

 

再打开我写的数据搬移程序:

 

 

然后修改对应的数据:

程序开始地址:修改比如$8100就修改为.ORG $8100

复制到什么地方就修改Addr_To,比如复制到$7000.BYTE $00,$70

从哪里开始复制就修改Addr_Begin,比如从$8200开始复制:.BYTE $00,$82

想到哪里结束复制就修改Addr_End,比如复制的数据源地址到$91FF.BYTE $FF,$91

也可以直接修改为 .BYTE $FF,$FF(复制目的地址到7FFF时会结束复制的)。

如果复制的数据最终超过7FFF,那么程序会结束复制,7FFF后面是程序块,不能乱搞。

中断地址可以不管,因为在RESET中中断已经禁用了,程序不会被中断。

后面的不用管。

 

设置完数据后单击编译:

 

然后保存编译文件:

 

选择二进制方式保存:

 

 

Hxd打开保存的二进制文件:

 

 

跳转到设置的程序开始$8100

 

 

 

回到FCEUX,转到NES内存的$8100对应的ROM地址:

 

 

 

 

 

然后把Hxd里编译的数据搬移程序复制后粘贴到ROM里:

 

 

 

然后转到NES内存的$8000对应的ROM地址:

 

 

 

 

 

 

写上如下程序:

A9 80 8D 01 A0 20 00 81  

LDA #$80

STA $A001 可写方式开启SRAM

JSR $8100 跳转到子程序$8100

 

然后把Hxd里被覆盖的程序复制过来粘贴在后面:

 

 

 

末尾补上一个0x60

RTS 子程序返回

 

然后单击运行,ROM音乐响起,正常运行:

 

 

然后转到NES地址$7000

 

 

 

 

 

可以看到,$7000-7FFF都被复制了一片数据。

测试没有问题,然后保存文件:

 

以上就是Mapper 4 的复制数据到SRAM$6000-$7FFF)教程的全部讲解。

后期修改ROM时遇到没有空间写程序时可以使用此方法进行扩容,将自己的其他程序放在 复制开始地址 至 复制结束地址 之间,这样ROM载入模拟器后会执行一次数据复制程序,把自己的程序复制到$6000-7FFF之间,后面的修改只需要跳转到$6000-$7FFF之间自己写的程序那儿就可以了。

 

原创粉丝点击