[FC][SRAM扩容教程(Mapper 4为例)]
本帖最后由 yandagui 于 2017-4-29 10:04 编辑时间:2017.4.28
作者:FlameCyclone
工具:FCEUX 2.2.3,Hxd 1.7.7.0,6502_Simulator
ROM:双截龙2(J).nes
适用:没有使用SRAM的ROM
首先用Hxd打开ROM:
http://www.emu618.org/data/attachment/album/201704/28/235808jb2ilfe482qq2gvx.jpg
然后扩容:
先看看任天堂产品系统文件对NES文件的说明:
NES文件格式
.NES文件为模拟用来储存NES卡带的映像。下面是一个.NES文件的结构。
偏移 字节数 内容
0-3 4 字符串“NES^Z”用来识别.NES文件
4 1 16kB ROM的数目
5 1 8kB VROM的数目
6 1 D0:1=垂直镜像,0=水平镜像
D1:1=有电池记忆,SRAM地址$6000-$7FFF
D2:1=在$7000-$71FF有一个512字节的trainer
D3:1=4屏幕VRAM布局
D4-D7:ROM Mapper的低4位
7 1 D0-D3:保留,必须是0(准备作为副Mapper号^_^)
D4-D7:ROM Mapper的高4位
8-F 8 保留,必须是0
16- 16KxM ROM段升序排列,如果存在trainer,它的512字节摆在ROM段之前
-EOF 8KxN VROM段, 升序排列
然后知道这个ROM有0x08个PROM和0x10个VROM
接下来扩展PROM位0x10个:
先把第0x04字节改为0x10,0x06字节的D1位置1(设置有SRAM):
http://www.emu618.org/data/attachment/album/201704/28/235810h825g5f52qf18gnc.jpg
由于mapper4的ROM在模拟器载入时会把最后16KB载入到整个64KB内存的C000-FFFF,因此需要在最后的16KB PROM(0x4000)前添加8x16KB PROM(0x20000大小),然后跳转到最后一个PROM的头部:偏移计算:
最后一个PROM的头部 = (总PROM - 1) x 0x4000 + 文件头0x10字节。
于是可以得到双截龙2的是:
(8-1)x 0x4000 + 0x10 = 1C010。
然后跳转到1C010:
http://www.emu618.org/data/attachment/album/201704/28/235810qnivczgnw6snxbwc.jpg
http://www.emu618.org/data/attachment/album/201704/28/235813t9rzfyad2zppya09.jpg
http://www.emu618.org/data/attachment/album/201704/28/235814gcbj2rdbq2qm2dcl.jpg
然后插入0x20000字节的FF:
http://www.emu618.org/data/attachment/album/201704/28/235815pzpze0npp0zztp1w.jpg
http://www.emu618.org/data/attachment/album/201704/28/235816x1tf2vnq4fqtf3t1.jpg
http://www.emu618.org/data/attachment/album/201704/28/235817qj6ec8a4tjfecto4.jpg
然后保存:
http://www.emu618.org/data/attachment/album/201704/28/235818youruere4uuior6f.jpg
http://www.emu618.org/data/attachment/album/201704/28/235819e1j5cq2500c19d1q.jpg
用FCEUX打开正常运行:
http://www.emu618.org/data/attachment/album/201704/28/235820edr21qd23xsz31m3.jpg
查看文件信息:
http://www.emu618.org/data/attachment/album/201704/28/235822kpslsm5zpqsq3ggm.jpg
http://www.emu618.org/data/attachment/album/201704/28/235826qpq20xtxbpp1bicx.jpg
接下来切页:
先打开十六进制编辑器:
http://www.emu618.org/data/attachment/album/201704/28/235827zpjpkytt9dyjdaqk.jpg
拉到滑块最后,看看重启中断
中断地址 中断 优先权
$FFFA NMI 中
$FFFC RESET 高
$FFFE IRQ/BRK 低
http://www.emu618.org/data/attachment/album/201704/28/235829jw80dn81z08c3pwn.jpg
RESET中断是ROM载入模拟器后最先开始运行的地方,只运行一次。
由此可知双截龙2的RESET中断$FF65。
接下来添加$FF65的执行断点:
打开调试器:
http://www.emu618.org/data/attachment/album/201704/28/235831td7x4hxzx6e94c4c.jpg
添加$FF65的执行断点:
http://www.emu618.org/data/attachment/album/201704/28/235834a41ttnlwkkvvm4gm.jpg
http://www.emu618.org/data/attachment/album/201704/28/235835ohjyjiy2j1ypgih2.jpg
单击确定:
http://www.emu618.org/data/attachment/album/201704/28/235837kyfwhxfheeih6iiw.jpg
然后重启ROM:
http://www.emu618.org/data/attachment/album/201704/28/235839qdddbcnq46pc8dkk.jpg
调试器此时弹出来:
http://www.emu618.org/data/attachment/album/201704/28/235842zqdgdx4l4ajf4hhh.jpg
然后打开Hxd,写一段mapper 4的切换bank程序:
先看看mapper 4的说明文档:
Mapper 4
$8000:模式号
位D0-D2:
0:选择2KB的VROM存储体映射到PPU的$0000
1:选择2KB的VROM存储体映射到PPU的$0800
2:选择1KB的VROM存储体映射到PPU的$1000
3:选择1KB的VROM存储体映射到PPU的$1400
4:选择1KB的VROM存储体映射到PPU的$1800
5:选择1KB的VROM存储体映射到PPU的$1C00
6:选择8KB的ROM存储体映射到$8000
7:选择8KB的ROM存储体映射到$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 将第0x0E号bank切到$8000-$9FFF
STA $8001
JSR $8000 跳转到子程序$8000
PLA 累加器A出栈
为何切换的bank号是0x0E呢?
因为在扩容ROM后,文件PROM结构为:
原来的0x07个16KB PROM + 自己的0x08个 16KB PROM + 原来的最后0x01个16KB PROM
Mapper 4切bank一次是切8KB,那么文件结构就是:
原来的0x0E个8KB PROM (00-0D) + 自己的0x10个8KB PROM (0E-1D) + 原来的最后0x01个8KB PROM (1E-1F)
因此选择扩容的第一个空白bank就是0x0E号bank。
http://www.emu618.org/data/attachment/album/201704/28/235845k9cz9yzd93y9wqu3.jpg
然后去调试器找RESET中断中可以放下切页程序的地方:
首先长度要小于等于自己写的切页程序。
可以看到FF7C可以使用(一般找程序中已经禁用中断后的地方,也就是找使用了SEI指令后的地方)
http://www.emu618.org/data/attachment/album/201704/28/235847mzp4drd65493g44i.jpg
然后跳转到$FF7C:
http://www.emu618.org/data/attachment/album/201704/28/235849bb9iddbie9i25cdi.jpg
http://www.emu618.org/data/attachment/album/201704/28/235851h00iptzt49pnimnz.jpg
http://www.emu618.org/data/attachment/album/201704/28/235853ex2st3byr1apsyaj.jpg
复制下可以被替换用于写切页的程序:
先选中,再复制:
http://www.emu618.org/data/attachment/album/201704/28/235855sukjzcchvujcprwa.jpg
http://www.emu618.org/data/attachment/album/201704/28/235857ihhh4tdzthldb542.jpg
在Hxd中新建一个文件,把复制的数据粘贴上去:
http://www.emu618.org/data/attachment/album/201704/28/235858lwomtuhaauu4zgw3.jpg
http://www.emu618.org/data/attachment/album/201704/28/235900u5feqza0xa0qoiyy.jpg
http://www.emu618.org/data/attachment/album/201704/28/235900ylc9o5bioociror5.jpg
然后回到十六进制模拟器:
转到$FF7C对应的ROM地址:
http://www.emu618.org/data/attachment/album/201704/28/235901pwi181wqukoguik4.jpg
http://www.emu618.org/data/attachment/album/201704/28/235904gvttvmhumybuu4ap.jpg
然后复制Hxd的切页程序,粘贴到这里:
http://www.emu618.org/data/attachment/album/201704/28/235904gvttvmhumybuu4ap.jpg
http://www.emu618.org/data/attachment/album/201704/28/235904vgotvnongjfnvvpg.jpg
http://www.emu618.org/data/attachment/album/201704/28/235903ewereerp1e4ew2d6.jpg
没有覆盖的用EA覆盖:
http://www.emu618.org/data/attachment/album/201704/28/235906up2ahocmhq6aayrr.jpg
打开调试器可以看到变化:
http://www.emu618.org/data/attachment/album/201704/28/235908bne3dauvru3tq66s.jpg
然后添加$FF7C执行断点:
http://www.emu618.org/data/attachment/album/201704/28/235908cncrj4t6snt3mnzq.jpg
http://www.emu618.org/data/attachment/album/201704/28/235909ypsndkb003qk2szk.jpg
http://www.emu618.org/data/attachment/album/201704/28/235910pwhkkcu26qf9b1a6.jpg
单击运行:
然后程序在$FF7C这里停下来了。
http://www.emu618.org/data/attachment/album/201704/28/235911wdbgz4191tclv19d.jpg
然后单击单步进入慢慢跟踪,直到跳转到$8000:
http://www.emu618.org/data/attachment/album/201704/28/235911hx62x31kbk99up26.jpg
然后打开6502_Simulator:
http://www.emu618.org/data/attachment/album/201704/28/235912z88wewnng8egwn38.jpg
再打开我写的数据搬移程序:
http://www.emu618.org/data/attachment/album/201704/28/235913nnzndjsfllnmall5.jpg
http://www.emu618.org/data/attachment/album/201704/28/235914icqv3b81nn4x3v13.jpg
然后修改对应的数据:
程序开始地址:修改比如$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中中断已经禁用了,程序不会被中断。
后面的不用管。
设置完数据后单击编译:
http://www.emu618.org/data/attachment/album/201704/28/235915b9zvy3r9gzam8aap.jpg
然后保存编译文件:
http://www.emu618.org/data/attachment/album/201704/28/235916jfe1dnrsq3es1lh5.jpg
选择二进制方式保存:
http://www.emu618.org/data/attachment/album/201704/28/235917gq606h0t6s46wst9.jpg
http://www.emu618.org/data/attachment/album/201704/28/235918rnrl1pgjjprrzg1c.jpg
用Hxd打开保存的二进制文件:
http://www.emu618.org/data/attachment/album/201704/28/235919j6x34c44xz8xoa34.jpg
http://www.emu618.org/data/attachment/album/201704/28/235920mdijy0qzy0cjcw0c.jpg
跳转到设置的程序开始$8100:
http://www.emu618.org/data/attachment/album/201704/28/235921sfjwjjuejj86pe99.jpg
http://www.emu618.org/data/attachment/album/201704/28/235923b18oyms7b8gs4nd2.jpg
http://www.emu618.org/data/attachment/album/201704/28/235923tomswzqk5m3m3mkb.jpg
回到FCEUX,转到NES内存的$8100对应的ROM地址:
http://www.emu618.org/data/attachment/album/201704/28/235925fw7pu61p79plpwqx.jpg
http://www.emu618.org/data/attachment/album/201704/28/235926k4qafy40y0qzzp4r.jpg
http://www.emu618.org/data/attachment/album/201704/28/235930g5zcuids2nu0jdjs.jpg
http://www.emu618.org/data/attachment/album/201704/28/235937ni8zfif9h8reyyfz.jpg
http://www.emu618.org/data/attachment/album/201704/28/235938nay752gqmkag71hk.jpg
然后把Hxd里编译的数据搬移程序复制后粘贴到ROM里:
http://www.emu618.org/data/attachment/album/201704/28/235939sxx7x4vxv7poysxs.jpg
http://www.emu618.org/data/attachment/album/201704/28/235940cgptp9nwwdwl9l1h.jpg
http://www.emu618.org/data/attachment/album/201704/28/235941p9lnqsmai9zjjznm.jpg
然后转到NES内存的$8000对应的ROM地址:
http://www.emu618.org/data/attachment/album/201704/28/235942p1vrccs77sit143l.jpg
http://www.emu618.org/data/attachment/album/201704/28/235944lfh8ff5hc8888tpf.jpg
http://www.emu618.org/data/attachment/album/201704/28/235945abllln5gnbblivlc.jpg
http://www.emu618.org/data/attachment/album/201704/28/235945syy2d01qzhoya9wy.jpg
写上如下程序:
A9 80 8D 01 A0 20 00 81
LDA #$80
STA $A001 可写方式开启SRAM
JSR $8100 跳转到子程序$8100
http://www.emu618.org/data/attachment/album/201704/28/235946a57w5g49r5rhcc0g.jpg
然后把Hxd里被覆盖的程序复制过来粘贴在后面:
http://www.emu618.org/data/attachment/album/201704/28/235947b167yz6ssmp69gs2.jpg
http://www.emu618.org/data/attachment/album/201704/28/235950vyozify499f0jnxi.jpg
http://www.emu618.org/data/attachment/album/201704/28/235949f8pw805n2j0jf3np.jpg
末尾补上一个0x60:
RTS 子程序返回
http://www.emu618.org/data/attachment/album/201704/28/235951gshs3q0s63c2j1h6.jpg
然后单击运行,ROM音乐响起,正常运行:
http://www.emu618.org/data/attachment/album/201704/28/235951qvkculbq5zuvlffl.jpg
http://www.emu618.org/data/attachment/album/201704/28/235952bq3y7to3exztblgx.jpg
然后转到NES地址$7000:
http://www.emu618.org/data/attachment/album/201704/28/235954xnl97u0ddac1p1qc.jpg
http://www.emu618.org/data/attachment/album/201704/28/235955sc5nf1kfn1nmn9kc.jpg
http://www.emu618.org/data/attachment/album/201704/28/235957wir9nz1rvar9repj.jpg
http://www.emu618.org/data/attachment/album/201704/28/235957q6ox1ytdlt6dcere.jpg
http://www.emu618.org/data/attachment/album/201704/28/235959diasiccjacecc9cb.jpg
可以看到,$7000-7FFF都被复制了一片数据。
测试没有问题,然后保存文件:
http://www.emu618.org/data/attachment/album/201704/29/000000f9ktxiv8k329eh29.jpg
以上就是Mapper 4 的复制数据到SRAM($6000-$7FFF)教程的全部讲解。
后期修改ROM时遇到没有空间写程序时可以使用此方法进行扩容,将自己的其他程序放在 复制开始地址 至 复制结束地址 之间,这样ROM载入模拟器后会执行一次数据复制程序,把自己的程序复制到$6000-7FFF之间,后面的修改只需要跳转到$6000-$7FFF之间自己写的程序那儿就可以了。
**** Hidden Message ***** 好多内容没有心情看了、、、、、 火纹外传扩容就可以汉化? 非常好的教程!👍 {:4_104:}来学习学习感谢分享 看一下楼主的教程,非常好。 好东西,看看 进来学习。
页:
[1]