EMU618社区

 找回密码
 立即注册
搜索
查看: 613|回复: 8

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

[复制链接]

签到天数: 39 天

[LV.5]常住居民I

发表于 2017-4-29 00:16:31 | 显示全部楼层 |阅读模式
本帖最后由 yandagui 于 2017-4-29 10:04 编辑 ) G, O3 W5 O$ u( m

  d: @5 T: @& c* c! z+ s9 E[FC][SRAM扩容教程(Mapper 4为例)]2 @$ v, d* a, m7 ?! O

2 i2 u6 S( q, m% `; U6 q2 z时间:2017.4.28! a) @& s) Q2 ]5 C  ^
作者:FlameCyclone5 m* N# i- [1 U  N! _( U" O- i! q
工具:FCEUX 2.2.3,Hxd 1.7.7.0,6502_Simulator
5 D8 X5 [! W$ z, GROM:双截龙2(J).nes
1 S! @9 ~5 l0 Q5 H' h" w7 H, Y4 I- j适用:没有使用SRAM的ROM8 i. F; s6 q4 ?

; G8 J: n1 P0 T. f( J" V首先用Hxd打开ROM:7 h( {- }: o2 d' O4 g9 M4 m

" [6 S0 P) i% `/ m8 y3 x然后扩容:
0 o. e, b+ h8 T8 b  B0 C
; F! V. |6 `3 C' y0 A. R
  x# t" K# s9 a# o+ r+ _. I8 L+ }! E0 j, G- \: o& Y. `: ~
' E% ~' C9 ~% o& F
; N& Q$ W$ c1 |
3 k" i! w) x9 a$ a8 i! r

2 Z6 ^8 ~4 c7 i/ ]8 Y0 {" |2 ^9 R
9 e. T# a+ a/ _0 ^# k1 z
- C3 Z$ Y' B$ a6 t; [先看看任天堂产品系统文件对NES文件的说明:
4 Q* j4 J3 O8 X. SNES文件格式4 B) s% M; k" [" ?/ o* U# N1 M
.NES文件为模拟用来储存NES卡带的映像。下面是一个.NES文件的结构。
$ S( D. ]" V  N, s偏移         字节数         内容 : `) E0 j; [0 }2 U7 i
0-3         4         字符串“NES^Z”用来识别.NES文件 / A7 D2 M; P5 q+ H/ c7 A& ]
4         1         16kB ROM的数目
) A" W, o# C" v2 b9 V' S" f, Y5         1         8kB VROM的数目 ! c0 I: M5 P1 s& v7 e( b$ y
6         1         D0:1=垂直镜像,0=水平镜像 " l" H$ W* d: v" M& T, M" N
                    D1:1=有电池记忆,SRAM地址$6000-$7FFF
1 i' }2 `1 s. a+ _, J$ K; Y                    D2:1=在$7000-$71FF有一个512字节的trainer ! Y5 |' R( h- X9 X
                    D3:1=4屏幕VRAM布局 ) z  f4 K" ^# `# H% W/ b# I
                    D4-D7:ROM Mapper的低4位
0 H# ?( U. ]" s0 c7         1         D0-D3:保留,必须是0(准备作为副Mapper号^_^) 1 O6 v: G0 b% I( {! L; v
                    D4-D7:ROM Mapper的高4位
- C: m2 X- N9 _8 _8-F         8         保留,必须是0 8 K. P/ i# \6 d4 O2 j
16-         16KxM         ROM段升序排列,如果存在trainer,它的512字节摆在ROM段之前 : o% v7 f$ U& U# g
-EOF         8KxN         VROM段, 升序排列
7 q8 |5 A- b& p8 T: D3 L% x+ S) S! C
然后知道这个ROM有0x08个PROM和0x10个VROM
  x# @' [0 V' p' ~接下来扩展PROM位0x10个:
$ o0 L6 \/ b4 ^# b! V' P4 d& ^先把第0x04字节改为0x10,0x06字节的D1位置1(设置有SRAM):
0 \$ n- d. Q. z) Q7 {* G
/ G$ `& R9 O* w) h  k4 p由于mapper4的ROM在模拟器载入时会把最后16KB载入到整个64KB内存的C000-FFFF,因此需要在最后的16KB PROM(0x4000)前添加8x16KB PROM(0x20000大小),然后跳转到最后一个PROM的头部:偏移计算:8 @/ U8 ?+ F) H1 O& o0 C
最后一个PROM的头部 = (总PROM - 1) x 0x4000 + 文件头0x10字节。
+ j2 |. h3 @8 a1 B0 S3 N于是可以得到双截龙2的是:
( J5 q; N- u) T  R) x4 F(8-1)x 0x4000 + 0x10 = 1C010。
* l. j8 a! k) @5 J然后跳转到1C010:/ ]5 r4 G+ D# _( W" }! J" N

5 O0 G+ @4 P# |, M: j' K
& D- \9 V+ h5 M& _9 ^2 J
. ?( u7 d9 K: q4 Y8 c然后插入0x20000字节的FF:3 r6 S) N$ f" ^% M

8 m% ^( g7 y' ~' j5 K4 _1 r; c
* B4 r# e: z' D- V: l$ \+ [* Z7 S3 d1 `
然后保存:! ^( O2 w# i7 ]+ q" s
" u6 T: ]6 I6 q  S  G" d
, e' _1 L& D! D1 [9 y3 ~
用FCEUX打开正常运行:' ]$ N1 |( Z$ ^- [* C
( `3 V& a& B/ F# ]' g
查看文件信息:
! ]8 W; ?" w  N: X' N# m
9 E; n3 l- p1 B: _" t
! }2 B5 D6 d* u0 u! t6 u接下来切页:5 t# d7 u8 q0 ~( {2 T$ m
先打开十六进制编辑器:7 H( J2 N+ A. g/ |' ~

1 c/ ]' i7 O0 C3 {拉到滑块最后,看看重启中断" U, m' @: m: h, U/ X
中断地址         中断         优先权
  |' o) [2 \9 n8 B- e7 _$FFFA         NMI         中
8 t5 u5 X* G: Q+ L: m; I. ?" t$FFFC         RESET         高
; W# g" N# h; d, ~$FFFE         IRQ/BRK         低   e, C" k+ w# I4 x9 @. D
! J- \% T5 G9 o0 h$ ^3 f6 ~
RESET中断是ROM载入模拟器后最先开始运行的地方,只运行一次。
2 H; h5 f* Y7 z# X/ E$ Q由此可知双截龙2的RESET中断$FF65。5 X9 ?2 `; F5 D0 ^! s5 A
接下来添加$FF65的执行断点:5 b+ M) a; h& S2 c
打开调试器:
' m1 [; t$ K+ E1 i# i. K  F7 M; R# K
# b) w, d! U  ~" d! U添加$FF65的执行断点:! c* g, H( r% ?5 N( z

, Z$ D9 P- f# F$ D' C% B- b% c* F* C/ o* s

# c" ^, x. Q! b# D+ b0 w; ^单击确定:4 Z- q1 ]8 {6 i" \+ H- p

) n: W% V. p/ ^( s/ T: \
: F' {/ J) t; U然后重启ROM:6 d( V# h/ N, \& x; {

, I8 B  H! R2 ?  t2 G' k调试器此时弹出来:* K' _7 U' x, \& p

$ K$ P4 ?* v5 N$ _然后打开Hxd,写一段mapper 4的切换bank程序:
/ y( G( g8 N5 r/ i8 r$ D! `+ V先看看mapper 4的说明文档:4 ^2 ^3 o$ d. y% U+ r$ @6 `4 o
Mapper 4
2 l, q6 |+ {: v2 _  r
+ ^5 s6 b1 V! b: V9 y' x' a9 r$8000:  模式号3 k, ^2 H6 g* Y- b
        位D0-D2:
6 R% k; m& U/ Q- i& z        0:选择2KB的VROM存储体映射到PPU的$0000+ v/ n5 U3 U* I. ]  B) ~
        1:选择2KB的VROM存储体映射到PPU的$0800
) S1 y" j6 K7 U: g" B! ^        2:选择1KB的VROM存储体映射到PPU的$1000
5 G! N6 D' ]/ V  F2 q! e        3:选择1KB的VROM存储体映射到PPU的$14004 r) d+ N3 o1 G
        4:选择1KB的VROM存储体映射到PPU的$18002 t" y* b9 ^8 C1 j' J
        5:选择1KB的VROM存储体映射到PPU的$1C00
/ ^/ f" w' R( Q9 I3 i, ^        6:选择8KB的ROM存储体映射到$8000
2 G1 D) S. V+ a# a1 D# j5 w        7:选择8KB的ROM存储体映射到$A000) N" A5 l0 `  w! l, r! n/ D4 d  L
        位D6:
% Y3 y4 w/ T6 J! |        0:允许擦写$8000和$A0003 u% M3 ^2 d* L  G% B
        1:允许擦写$A000和$C000
, ]1 g; s3 a8 H! h% |, n9 I        位D7:- O) V2 B- X% f0 z4 l5 z, a
        0:模式号D0-D2使用普通地址8 f  u  n+ C- g
        1:模式号D0-D2地址异或$1000
; f7 E& L% ]6 y8 E6 q
5 l7 d( w) w1 }9 ]5 \$8001:  模式页面号
) O( `3 c3 n: k# c        写入一个数(00-07),切换存储体到对应地址
# F2 T0 n( ]. I5 ~& M
0 f  P* R# b( V2 }8 N: w* x' ]$A000:  镜像选择9 ~. U$ s  O7 g% {* i
        0:垂直镜像! R! H* `( K6 V
        1:水平镜像
6 [1 l) H& \! i0 ?' S- S
# T& a: Y) x) C" ^$A001:  SaveRAM 切换
( U9 Z7 C8 t. d- M! o4 U" ~. m        0:禁用$6000-$7FFF: b/ o$ `; R( u1 V9 f# m
        1:启用$6000-$7FFF+ o5 d; v/ b$ I; H. ?

, F! ]# y% \0 O; L$C000:  IRQ计数器6 z' c: [" y9 }
        IRQ计数器的值存储在此处  a. N/ u, O3 d8 ]* r

3 p6 z0 m  G+ g5 N! ]# J1 ~$C001:  IRQ暂存器8 z  |+ r  x: [7 G
        IRQ暂存器的值存储在此处" X1 ^+ c% U' m  L1 a& b$ r

" E* a8 `5 Y2 h( [7 [3 S$E000:  IRQ控制计数器06 _* u1 g" o  l$ d
        向这里写入任何数来关闭IRQ,并从暂存器中拷贝数据开始计数,进入IRQ
1 {8 {9 I2 P6 A9 S3 y9 M8 s2 b2 j: B) x3 ?6 P
$E001:  IRQ控制计数器1$ _- l. ]: A1 S0 }4 ^, ]
        向这里写入任何数,允许IRQ(退出IRQ,允许下一个IRQ进来)
6 E& J6 G3 }9 W6 b3 S+ Q+ w  V* K/ [/ Q( o% K
那么就写段切页到$8000-$9FFF,然后跳转到$8000的切bank程序:
6 r: p% \2 q3 R2 S- {& p! Q48 A9 06 8D 00 80 A9 0E 8D 01 80 20 00 80 68' e; n( O3 r* G  e& _1 }# t
PHA      累加器A入栈* z, S; K% t% T; i
LDA #$06    设置切bank地址为$8000-$9FFF* a$ j# O0 I( M* J2 d$ J; |+ H2 R" J
STA $80000 Q9 u0 U) F7 p0 h% ?4 M0 A
LDA #$0E    将第0x0E号bank切到$8000-$9FFF* S: j1 j; w9 i0 {& A3 G. M
STA $8001* ~# _3 f1 z+ e, s3 P3 V& N& l
JSR $8000    跳转到子程序$8000
$ e  I+ N! R9 PPLA     累加器A出栈: _2 b2 ^) e- w# p4 L+ Q) |

8 @' c4 T+ n! f1 p' R6 ?3 w为何切换的bank号是0x0E呢?
, ^% k: t9 o9 I因为在扩容ROM后,文件PROM结构为:
) q% ]9 M7 j9 T8 ^! Y" Z原来的0x07个16KB PROM + 自己的0x08个 16KB PROM + 原来的最后0x01个16KB PROM
( K; w3 h; c. K; N/ _; `1 \! ~
$ L. g' T2 k1 Z  L2 ]! _Mapper 4切bank一次是切8KB,那么文件结构就是:
* w& I- x0 T3 p. L! z; g. L8 @原来的0x0E个8KB PROM (00-0D) + 自己的0x10个8KB PROM (0E-1D) + 原来的最后0x01个8KB PROM (1E-1F)
+ I# ?1 m7 F. d: C5 X( f; N因此选择扩容的第一个空白bank就是0x0E号bank。
  A# m. A; h7 Z4 `) O( r7 l& U% h: T+ l- R3 m1 h
: @/ I1 p- h: g' U* F8 S4 a# R
然后去调试器找RESET中断中可以放下切页程序的地方:
: U$ w4 w- I0 w! w! U- R+ [首先长度要小于等于自己写的切页程序。4 u/ e  V' v2 g/ |
可以看到FF7C可以使用(一般找程序中已经禁用中断后的地方,也就是找使用了SEI指令后的地方)3 k. m4 o/ A) X0 K" |3 h8 d
. ]- }+ t4 {+ z5 ^) T7 ?4 t; O3 z
然后跳转到$FF7C:9 V/ e6 `. k8 {6 N
* A( [- }+ D& S
5 ^/ Z4 A- A4 `5 ?/ T% N

3 N9 X7 B% p% W* n6 H+ b! P: p. s4 O( |9 Q  k8 a* U
复制下可以被替换用于写切页的程序:
+ D. a& s3 H, @' O; r先选中,再复制:- r0 B5 ?. V$ o( h

/ e/ [5 |1 l& d" O
5 T) e" c) U1 W7 d8 g6 z6 W" m在Hxd中新建一个文件,把复制的数据粘贴上去:# W; _" O# x$ }5 u5 Y

: P4 K5 B. O: ~: @5 D( q1 ]9 Z. e  J( D& \' F7 n( Y" b
$ ]4 I% U9 U' P) R
: A. T* c0 E1 T4 n
然后回到十六进制模拟器:
3 V% s& P/ c* [9 d# i  \/ I' p转到$FF7C对应的ROM地址:  q, Q* z3 C0 M/ @/ |

) [' `& }# `  f8 B( N/ h1 B" O9 a6 z+ |
然后复制Hxd的切页程序,粘贴到这里:  Y+ M! ?! o9 H* I: `9 h+ P

- d! U9 e% Q+ d6 |# H  S! [8 I. @% `% c7 V

! w- I# Z; }; n, o, O) `# d( q没有覆盖的用EA覆盖:
* W- N3 G1 M+ o# O6 f0 i$ e& d4 q% p1 h% e5 }8 w
打开调试器可以看到变化:* h3 }& A& y* X6 u8 C! j( P4 p6 R

+ N- P" ~/ Y8 x' ?9 X9 U) v然后添加$FF7C执行断点:  t2 R( d8 F# H5 H. n
! H+ C# R4 b5 v9 r& a
: q1 _3 z# V$ X5 ]! Z7 }- ~

: C9 p- ?6 n3 ?. c$ W) j单击运行:2 \. g5 G% i7 W+ C( r
然后程序在$FF7C这里停下来了。  M; q) R0 ~8 y' ]# i% T" E
: q4 r2 E8 F# K0 x5 u- j7 _
然后单击单步进入慢慢跟踪,直到跳转到$8000:* m4 x, a0 \: j5 Q5 j. K7 t0 d
  f! Y* }2 y! f; k  j3 q6 ~$ ?
然后打开6502_Simulator:; V6 W6 T) {3 g7 e" A
) S2 t' b6 ~. ]1 d+ C: J3 x, @
再打开我写的数据搬移程序:
0 `6 F7 @. [$ m& g/ e' k! U9 h& v: ^9 i2 F# p9 D0 R, U
' `! d2 h% f! h  j1 a2 ]; J6 G# O
然后修改对应的数据:) |" j4 \( |# l: ]/ `
程序开始地址:修改比如$8100就修改为 .ORG $8100
, `/ K, a  b8 D( y5 I& |复制到什么地方就修改Addr_To,比如复制到$7000: .BYTE $00,$70
% p& G1 z  N3 r" H8 b: f从哪里开始复制就修改Addr_Begin,比如从$8200开始复制: .BYTE $00,$82- T( q, l% Z  I
想到哪里结束复制就修改Addr_End,比如复制的数据源地址到$91FF: .BYTE $FF,$91
; t- }, R8 K1 C: {也可以直接修改为 .BYTE $FF,$FF(复制目的地址到7FFF时会结束复制的)。
5 L+ n- A7 u/ [" W' t4 x如果复制的数据最终超过7FFF,那么程序会结束复制,7FFF后面是程序块,不能乱搞。. ~/ [3 `0 [1 o- @' }+ T
中断地址可以不管,因为在RESET中中断已经禁用了,程序不会被中断。
+ m: t1 r% d8 |3 S6 q1 k0 h后面的不用管。' f% \3 j! |" L% I  M

/ ~" A8 E+ d5 Y设置完数据后单击编译:, G+ K% y  G+ o& L3 r+ R
8 f) K3 A8 V1 X/ q, N
然后保存编译文件:- Q9 e9 W; U3 E- b4 }% W$ j

4 x# F& ^! q7 H6 ~选择二进制方式保存:
8 a% n7 c8 Y  W# R$ C; I0 t9 V
, L: R: a9 `% E+ o9 ~0 c; d$ C7 i& ~# T6 N/ W/ T
用Hxd打开保存的二进制文件:9 ^/ ], m8 I- f* E4 X. P' }
# v6 f4 {% Q: g

# {* l$ {) M9 N% G8 |5 M2 j9 D! V6 e2 Z跳转到设置的程序开始$8100:" e# |" C  N% [: V$ x7 c

* A4 P1 k/ I. c2 Q
  Y* h, M7 l# a$ v! j$ m$ k  [6 y; P( g9 t2 L  I1 I
回到FCEUX,转到NES内存的$8100对应的ROM地址:
  X* ^+ v- z7 K+ _' |
# B2 l* L4 B% a; [0 H' M% g& k; Y# ~/ s8 y

3 i' B! o8 y# P; F* ]
: w. ?/ L/ @; x
6 V$ @' l6 v% ]9 b3 h  Y然后把Hxd里编译的数据搬移程序复制后粘贴到ROM里:1 U4 ~3 ]9 D" _" A6 a6 ?

5 u3 S! H! U$ m9 x' y; \! Z# J8 `

4 c  x2 |- s! ^0 ^, y然后转到NES内存的$8000对应的ROM地址:
+ Z; F4 n( V+ c8 k, \% a, s+ X, s, W* F8 C  o: A, @2 y

$ X& M$ g! E$ _
0 A* c* d% l8 B' h1 f/ }6 R9 g1 x0 a" Q0 Q! J  H* a8 O
写上如下程序:
% ^& v* |. m; S, j! ^A9 80 8D 01 A0 20 00 81  
9 k7 m, S( q% @) Y. n: b+ q: zLDA #$80
' w$ ^. Z! i8 R: l/ mSTA $A001 可写方式开启SRAM
6 Q( L; R8 j) B7 d/ YJSR $8100 跳转到子程序$8100
8 G+ o; e9 X; x/ ?$ B( F: [
; s* g! m! t9 v/ w+ N然后把Hxd里被覆盖的程序复制过来粘贴在后面:0 b! X( ?0 Z7 I1 V# U% j

/ A# m, |/ q" c
7 d' a) E) |- k  O# r" w. x' Y2 u0 Q; u$ F1 D$ g
末尾补上一个0x60:" R. @9 x5 U! T6 {# W3 _
RTS 子程序返回
, a3 H5 O" {# N/ J
( S7 p' g$ {) v2 O然后单击运行,ROM音乐响起,正常运行:; |6 c$ y+ o6 K: Q

7 l+ ?1 [8 P  I! T2 P' r  U
, A2 h' A1 i6 ~# m, Q然后转到NES地址$7000:
3 K4 B$ r6 b! ^3 W' @+ q3 h+ d' ]/ v3 z& r% B0 \* k0 E: k
, |' \/ @% b. y" [
( _* C5 w2 G7 N' t( ~) b; A
/ l- G# N! }1 P9 u

/ _  e7 q7 {2 f7 w( i+ |7 f( \' P可以看到,$7000-7FFF都被复制了一片数据。
( b/ ?5 l/ J3 r) Z- U8 r+ M测试没有问题,然后保存文件:
' H8 I/ E$ \5 U/ l" d
: `! @! i  ~$ }3 u以上就是Mapper 4 的复制数据到SRAM($6000-$7FFF)教程的全部讲解。- F8 f8 n. R6 {, w
后期修改ROM时遇到没有空间写程序时可以使用此方法进行扩容,将自己的其他程序放在 复制开始地址 至 复制结束地址 之间,这样ROM载入模拟器后会执行一次数据复制程序,把自己的程序复制到$6000-7FFF之间,后面的修改只需要跳转到$6000-$7FFF之间自己写的程序那儿就可以了。
5 L3 X/ B/ s2 O. h) ^
游客,如果您要查看本帖隐藏内容请回复

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

签到天数: 2060 天

[LV.Master]伴坛终老

发表于 2017-4-29 01:07:47 | 显示全部楼层
好多内容没有心情看了、、、、、
[发帖际遇]: liujunbtx为灾区捐款 6 个 柠檬. 幸运榜 / 衰神榜

签到天数: 1180 天

[LV.10]以坛为家III

发表于 2017-4-29 21:00:16 | 显示全部楼层
火纹外传扩容就可以汉化?

签到天数: 1434 天

[LV.10]以坛为家III

发表于 2017-4-29 22:24:54 | 显示全部楼层
非常好的教程!👍

该用户从未签到

发表于 2017-7-25 15:03:46 | 显示全部楼层
{:4_104:}来学习学习感谢分享
回复 支持 反对

使用道具 举报

签到天数: 30 天

[LV.5]常住居民I

发表于 2017-7-27 21:47:15 | 显示全部楼层
看一下楼主的教程,非常好。
回复 支持 反对

使用道具 举报

头像被屏蔽

签到天数: 5 天

[LV.2]偶尔看看I

发表于 2018-2-8 21:36:34 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

签到天数: 57 天

[LV.5]常住居民I

发表于 2018-10-23 13:32:34 | 显示全部楼层
好东西,看看
回复 支持 反对

使用道具 举报

签到天数: 208 天

[LV.7]常住居民III

发表于 2024-3-22 21:01:24 | 显示全部楼层
进来学习。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|国治模拟精品屋 ( 沪ICP备15012945号-1 )

GMT+8, 2025-1-2 00:58 , Processed in 1.103515 second(s), 22 queries , Gzip On.

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表