1、1+-+| 任天堂红白机 ( NES ) 文档 | 版本.2.00 |+-+-+| 目录 |+-+1. 说明A. 弃权声明B. 为什么?C. 任务D. 献给E. 鸣谢2. AcronymnsA. 内部B. 硬件3. CPUA. 一般信息B. 内存地址C. 中断D. NES 定制细节E. 注意4. PPUA. 概述B. 内存映射C. Name TablesD. Pattern TablesE. Attribute TablesF. 调色板G. Name Table 镜像H. 调色板镜像I. 背景卷轴J. 屏幕和子图形的层K. 子图形和 SPR-RAML. 子图形 #0 点击标记M. 水平和竖直空
2、白N. $2005/2006 矩阵编码O. PPU 怪癖P. 注意5. pAPU6. 手柄, 摇杆, 扩展端口A. 概述B. 光线枪2C. 四人分插D. 摇杆E. Power PadF. R.O.B (Robot Operated Buddy)G. 信号H. 扩展端口I. 注意7. 硬件内存镜像8. 寄存器9. 文件格式A. iNES 格式 (.NES)10. 为 NES 设计程序A. 概述B. CPU 注意事项C. PPU 注意事项11. 模拟器A. 概述B. CPU 注意事项C. PPU 注意事项D. APU 注意事项12. 引用材料A. CPU InformationB. PPU Inf
3、ormationC. APU InformationD. Memory Mapper InformationE. Mailing ListsF. WWW SitesG. Hardware Information+-+| 1. 说明 |+-+A. 弃权声明-我绝不为本文的信息所造成的结果负责. 这些都是公开的信息, 并且不应当被用于商业用途.如果你打算将本文用于商业用途, 请在开发之前与我联系, 使我能够和你商讨你的项目的大纲.我并没有打算在资金上阻碍任何人: 如果你打算进行真的 NES开发, 与任天堂美国公司或任天堂公司联系将是明智的. 它们的地址是:3Nintendo of America
4、Nintendo Company, Ltd.P.O. Box 957 60 FukuineRedmond, WA 98073 Kamitakamatsu-cho,USA Higashiyama-ku,Koyoto 602, JapanAll titles of cartridges and console systems are registered trademarks of theirrespective owners. ( 我不认为有必要把他们一个一个的单独列出来 ).B. 为什么?-在本文完成时, 只有一片概括了 NES内部的文章: Marat Fayzullin 的文章, 也就是 “
5、NES.DOC“.虽然 Fayzullin 的文章在很多地方有缺陷, 它提供了一个强大的基础, 并且它里面确实有对如何完成那个小黑匣子有一定的陈述.我抓住了扩展 “NES.DOC“ 的机会, 是以其他人的发现和我的经验为基础. 这些经验使得这篇文章变成它今天的样子. 本文开头部分像是 Fayzullin 的文章经过了缩写和一些修改的复制品. Marat Fayzullin 本人后来得到了我的文章, 之后他就像别人推荐这篇文章.在我开来, 如果没有 Marat 的 “NES.DOC“, 我将永远没有写这一篇的动机.C. 任务-本文的目标很简单: 提供关于 NES的最准确和最新的信息, 以及 Fa
6、micom 的相关信息.D. 献给-我把本文献给 Alex Krasivsky. Alex 是一个很好的朋友, 并且在我眼里, truly started theball of emulation rolling. 开心的时间和悲伤的时间, Alex 都在.Spasibo, Alex; umnjy Russki.E. 鸣谢-感谢所有帮助使本文成文今天的样子的人. 没有你们我将无所作为.Alex Krasivsky - bcatlapkin.rosprint.ruAndrew Davie4Avatar Z - Barubary - Bluefoot - CiXeLChi-Wen Yang - C
7、hris Hickman - D - slf05cc.usu.eduDan Boris - David de Regt - Donald Moore - Fredrik Olsson - flubbahem2.passagen.seIcer Addis - Jon Merkel - jpm5974omega.uta.eduKevin Horton - Loopy - Marat Fayzullin - fmscs.umd.eduMark Knibbs - mark_Martin Nielsen - mnielsenget2net.dkMatt Conte - Matthew Richey -
8、mr6vandrew.cmu.eduMemblers - MiKael Iushin - acctulatelecom.ruMike Perry - mj-perryuiuc.eduMorgan Johansson - morgan.johanssonmbox301.swipnet.seNeill Corlett - corlettelwha.nrrc.ncsu.eduPat Mccomack - Patrik Alexandersson - patrikushem2.passagen.sePaul Robson - AutismUKRyan Auge - Stumble - Tennesse
9、e Carmel-Veilleux - veilleuxameth.orgThomas Steen - Thomas.STony Young - KBAAAVince Indriolo - FireBug - 特别感谢 Stumble, 他通过 IRC提供了无限的信息, 甚至不睡觉.5+-+| 2. Acronymns |+-+A. 内部-CPU - 中央处理器: Self-explanitory. NES 使用一个标准 6502 ( NMOS )PPU - 图形处理器: 用来控制图形,活动块和其他视频相关特点pAPU - pseuedo-Audio 处理器: 固化于 CPU; 产生 (5)
10、声音通道的波形: 四个 (4) 模拟和一个 (1) 数字. 在 NES内部没有处理音频的物理芯片.MMC - 大量内存控制器: 微型控制器, 用来控制使 NES游戏使用 6502的64Kbyte以外的存储器.他们也可以被用来控制使用 CHR-ROM,也许被用来产生“特别效果” ,比如强制和中断,以及其他一些.VRAM - 图形储存器: 这个储存器在 PPU内部. NES中安装了 16kbits 的VRAM.SPR-RAM - 子画面储存器: 用来储存子画面,共 256 bytes. 虽然他也在 PPU内部,但不是 VRAM或者ROM的一部分.PRG-ROM - 程序只读储存器: 存储程序代码的
11、存储器. 也可以认为是通过 MMC控制的扩展存储器中的代码部分.PRG-RAM - 程序可写存储器: 于 PRG-ROM同义,不过这个是 RAM.CHR-ROM - 角色只读存储器: 在 PPU外部的 VRAM数据, 通过 MMC在 PPU内部与外部交换,或者在启动队列中“读入”VRAM.VROM - 与 CHR-ROM同义.SRAM - 存档可写存储器: 一般用来保存 RPG游戏的进度. 就像最终幻想系列的“水井” ,和“塞尔达传说”.WRAM - 与 SRAM同义.DMC - 调制通道: APU中处理数字信号的通道. 通常被认为是 PCM (Pulse信号调制器)通道.EX-RAM - 扩
12、展存储器: 在任天堂的 MMC5中使用的,允许游戏扩展 VRAM的容量.B. 硬件-NES - 任天堂娱乐系统: Self-explanitory.Dany - 与 Famicom同义(硬件范围).Famicom - 与 NES同义,但不支持原始的 DMC数字音频重放.6FDS - Famicom磁盘系统: 安装在 Famicom顶部,支持 3“双面游戏软盘.+-+| 3. CPU |+-+A. 一般信息-NES使用一个定制的 NMOS 6502 CPU, 由 Ricoh设计制造. 他最初的定制是添加了音频.NTSC制式的 NES频率是 1.7897725MHZ, PAL 的是 1.77344
13、7MHZ.B. 内存地址-+-+-+-+-+| 地址 | 大小 | 标记 | 描述 |+-+-+-+-+| $0000 | $800 | | RAM | $0800 | $800 | M | RAM | $1000 | $800 | M | RAM | $1800 | $800 | M | RAM | $2000 | 8 | | Registers | $2008 | $1FF8 | R | Registers | $4000 | $20 | | Registers | $4020 | $1FDF | | Expansion ROM | $6000 | $2000 | | SRAM | $80
14、00 | $4000 | | PRG-ROM | $C000 | $4000 | | PRG-ROM |+-+-+-+-+标记图例: M = $0000 的镜像R = $2000-2008 每 8 bytes 的镜像(e.g. $2008=$2000, $2018=$2000, etc.)C. 中断-6502有三种 (3) 中断: IRQ/BRK, NMI 和 RESET.每一种中断都有一个向量. 向量是当中断触发时“转到”的指定位置的 16位地址.7IRQ/BRK在两种情况下触发,因此它有分开的名字: 当软件中断请求被执行 (BRK指令),或者硬件中断请求被执行 (通过 IRQ语句).RES
15、ET在启动时被触发. ROM 被读入内存,并且 6502转到指定的 RESET向量. 没有寄存器被修改,没有内存被清空; 这些仅仅发生在启动时.NMI的意思是 Non-Maskable Interrupt (不可屏蔽中断-译注),发生在每次刷新时(VBlank). 这些刷新的间隔依赖于所用的系统 (PAL/NTSC).NMI在 NTSC控制下刷新次数为 60次/秒, PAL为 50次/秒. 6502的中断潜伏期为七 (7) 个周期; 这也就是说需要需要七 (7) 个周期来移入和移出一个中断.大多数中断应当返回 RTI语句. 一些 NES游戏不使用这种方法,比如SquareSoft的“Final
16、 Fa-ntasy 1“的标题. 他们的中断使用一种非常奇怪的方式返回: 通过手动操纵堆栈,然后返回一个 RTS. 从技术上说这是有效的,但从精神上说这应当被避免.上述的中断使用下列的向量地址,它们在内存中的地址为:$FFFA = NMI$FFFC = RESET$FFFE - IRQ/BRK中断优先权如下:Highest = RESETNMILowest = IRQ/BRKD. NES订制细节-NES的 6502并不包括对 decimal模式的支持. CLD和 SED opcodes function normally, 但是 p中的 d bit在 ADC和 SBC中并未被使用. 在游戏中将
17、 CLD先执行于代码是普遍的行为,就像启动和 RESET时的 d 状态并不为人知一样.音频寄存器被放置于 CPU内部; 所有波形的发生也都在 CPU的内部.8E. 注意-请注意那两个独立的 16K PRG-ROM片断; 他们也许是线性的,但是他们是否独立依赖于游戏容量的大小. 有些游戏只用一 (1) 个 16K的 PRG-ROM,这就需要将他读入到$C000和$8000 之中 (两块内存都被写入-译注).大多数游戏将他们自己读入到$8000, 使用 32K PRG-ROM 空间. 第一个这样做的游戏是 Super Mario Brothers. 然而所有大于一 (1) 个 16K 容量的 PR
18、G-ROM也都把他们自己读入$8000.这些游戏使用 Memory Mappers在 PRG-ROM内外交换数据,CHR-ROM 中也一样.当遇到 BRK时,NES 的 6502将 CPU状态标记推入有 b CPU bit 集合的堆栈中. 在 IRQ或者 NMI时,CPU将状态标记推入清除了 b bit的堆栈中. 这样做是因为事实上硬件 IRQ (IRQ) 和软件 IRQ(BRK) 使用同样的向量. 例如,一个中断会使用下面的代码来区别上述两种中断:C134: PLA ; 拷贝 CPU状态标记C135: PHA ; 将状态标记返回到堆栈C136: AND #$10 ; 检查 D4 (b CPU
19、 bit)C138: BNE is_BRK_opcode ; 如果固定了,则它是一个软件 IRQ (BRK)执行 NMI中的 BRK将导致被推入的 b bit 被固定.6502在 opcode $6C 有一个 bug (绝对的间接跳跃). CPU并没有正确考虑到当 低字节 low-byte是$FF 时的有效地址. 例如:C100: 4FC1FF: 00C200: 23D000: 6C FF C1 - JMP ($C1FF)逻辑上说,这样将转到地址$2300. 然而,事实上计算中的高字节 *NOT* increased on a page-wrap, 事实上转到了$4F00.应当被注意的是 pa
20、ge wrappig并不发生在 间接地址索引模式 indexed-9indirect addressingmodes.由于 0页面 zero-page,所有 间接索引 indexed-indirect 的读写必须在计算后申请一个到有效地址的一个逻辑 与 AND #$FF. 例如:C000: LDX #3 ; 从 $0002+$0003 读间接地址 indirect address,C002: LDA ($FF,X) ; 不是 $0102+$0103.+-+| 4. PPU |+-+A. 概述-镜像 (也被称为“shadowing“) 是将特殊的地址或抵制范围通过硬件映射到其他地址的一种处理.B
21、. 内存映射-这里有两 (2) 片内存映射. 第一部分被称为 “RAM Memory Map“,是一段不算长的指向 NES本身物理 RAM的区域。第二部分是 “Programmer Memory Map“,是比较长的描述全部NES和他如何被使用以及如何被操作的内存区域.RAM Memory Map+-+-+-+| Address | Size | Description |+-+-+-+| $0000 | $1000 | Pattern Table #0 | $1000 | $1000 | Pattern Table #1 | $2000 | $800 | Name Tables | $3F0
22、0 | $20 | Palettes |+-+-+-+10Programmer Memory Map+-+-+-+-+| Address | Size | Flags | Description |+-+-+-+-+| $0000 | $1000 | C | Pattern Table #0 | $1000 | $1000 | C | Pattern Table #1 | $2000 | $3C0 | | Name Table #0 | $23C0 | $40 | N | Attribute Table #0 | $2400 | $3C0 | N | Name Table #1 | $27C0
23、 | $40 | N | Attribute Table #1 | $2800 | $3C0 | N | Name Table #2 | $2BC0 | $40 | N | Attribute Table #2 | $2C00 | $3C0 | N | Name Table #3 | $2FC0 | $40 | N | Attribute Table #3 | $3000 | $F00 | R | | $3F00 | $10 | | Image Palette #1 | $3F10 | $10 | | Sprite Palette #1 | $3F20 | $E0 | P | | $4000
24、| $C000 | F | |+-+-+-+-+C = Possibly CHR-ROMN = Mirrored (see Subsection G)P = Mirrored (see Subsection H)R = Mirror of $2000-2EFF (VRAM)F = Mirror of $0000-3FFF (VRAM)C. Name Tables-NES使用马赛克矩阵进行图形显示; 这样的格子被叫做 Name Table. 马赛克是 8x8像素 pixels.完整的 Name Table 有 32*30 个马赛克 (256*240 像素). 紧记: NTSC和 PAL单元在显示
25、上有不同的刷新率.Name Tables 之中的马赛克的资料被保存在 Pattern Table 之中 (continue on).D. Pattern Tables-Pattern Table 包括了 Name Table 所需要的 8x8 的马赛克. 他保存了 NES调色板中所有 16色的114-bit 颜色矩阵的低两 (2) 位 bit. 例如:VRAM Contents of Colour Addr Pattern Table Result- - -$0000: %00010000 = $10 -+ .1 Periods are used to%00000000 = $00 | 2.2
26、. represent colour 0.%01000100 = $44 | .3.3 Numbers represent%00000000 = $00 +- Bit 0 2.2. the actual palette%11111110 = $FE | 1111111. colour #.%00000000 = $00 | 2.2.%10000010 = $82 | 3.3.$0007: %00000000 = $00 -+ $0008: %00000000 = $00 -+%00101000 = $28 |%01000100 = $44 |%10000010 = $82 +- Bit 1%0
27、0000000 = $00 |%10000010 = $82 |%10000010 = $82 |$000F: %00000000 = $00 -+上面的 Pattern Table 的结果就是字符 A,就像右上角的 “Colour Result“ 部分显示的.E. Attribute Tables-Attribute Table 的每一个字节都描述了显示器上的一个 4*4 马赛克组. 有许多种方法来描述Attribute Table 中一 (1) 个字节的函数是怎样的:* 保存了 32*32 像素格子 中每 16*16 像素 的高两 (2) 位.* 保存了 十六 (16) 个 8x8 马赛克
28、中的 高两 (2) 位.* 保存了 四 (4) 个 4*4 像素格子 的高两 (2) 位.12这样说确实很乱; 下面的两个图表将有所帮助:+-+-+| Square 0 | Square 1 | #0-F represents an 8x8 tile| #0 #1 | #4 #5 | #2 #3 | #6 #7 | Square x represents four (4) 8x8 tiles+-+-+ (i.e. a 16x16 pixel grid)| Square 2 | Square 3 | #8 #9 | #C #D | #A #B | #E #F |+-+-+真正的 attribut
29、e byte 格式如下 (与上面的相比较):Attribute Byte(Square #)-33221100|+- Upper two (2) colour bits for Square 0 (Tiles #0,1,2,3)|+- Upper two (2) colour bits for Square 1 (Tiles #4,5,6,7)|+- Upper two (2) colour bits for Square 2 (Tiles #8,9,A,B)+- Upper two (2) colour bits for Square 3 (Tiles #C,D,E,F)F. 调色板-NES
30、有两个 16 色 “调色板“: 图形调色板和子图形调色板. 因为他们不储存物理RGB值,所以比起一个真正的调色板,它们更像 “查找表格“.写到 $3F00-3FFF 的 D7-D6 字节将被忽略.G. Name Table 镜像-需要紧记的一点是在理解 NES的时候,有许多镜像表格. 即使在使用 CHR-ROM-mapped Name Tables(mapper-specific).NES本身只有 2048 ($800) 字节的 RAM给 Name Tables. 然而,就像在 Subsection B 中所表现得那样 NES 有升至 四 (4) 个 Name Tables 的地址容量.13缺
31、省的是许多 carts 伴随的是 “水平“ 和 “垂直“ 的镜像,允许你修改 Name Tables 所指向的 NESPPU RAM 的位置. 这个镜像表格同时作用于两 (2) 个 Name Tables; 你不可以独自选择 Name Tables.下面的表格将帮助理解 NES中遇到的所有镜像类型. 请注意显示的地址 (大小为 12-bit) 都是 NES PPURAM 的 Name Table 的一部分; 有人为认为这些与 VRAM区域中的 “$2xxx“ 同义:Name NT#0 NT#1 NT#2 NT#3 Flags+-+-+-+-+-+-+| Horizontal | $000 |
32、$000 | $400 | $400 | | | Vertical | $000 | $400 | $000 | $400 | | | Four-screen | $000 | $400 | $800 | $C00 | F | | Single-screen | | | | | S | | CHR-ROM mirroring | | | | | C |+-+-+-+-+-+-+F = 依赖于扩展的 2048 ($800) RAM (kept on the cart) 的四屏镜像,导致四 (4) 个独立的物理Name Tables.S = 拥有映射表 mapper 的单屏游戏,允许你选择哪个 P
33、PU RAM区域来使用 ($000, $400, $800, $C00); 所有的 NT 都指向同样的 PPU RAM 地址.C = 映射表 #68 (Afterburner 2),允许你将 CHR-ROM 镜像到 NES 的 PPU RAM 区域中 Name Tables区域. 很自然的这使得 Name Table 成为 ROM 基础,并且不能对它写入. 然而,这个特点可以通过映射表本身进行控制,使得你打开或关闭这个特点.H. 调色板镜像-镜像发生在图形调色板和子图形调色板之间. 任何写入 $3F00 的数据都被镜像到 $3F10. 任何写入 $3F04的数据都被镜像到 $3F14,如此.
34、如此.在图形调色板和子图形调色板的高三 (3) 色 Colour #0 被定义为透明 (实际上那里储存的颜色不被显示).14PPU 使用 $3F00 来定义背景色.另一个长一些的解释,如下:* $0D 被写入 $3F00 (镜像到 $3F00)* $03 被写入 $3F08 (镜像到 $3F08)* $1A 被写入 $3F18* $3F08 被读入 累加器 accumulatorPPU 使用 $0D 作为背景色,不论 $3F08 饱含了 $03 的值 (因为所有的调色板中的 colour #0 都被定义为透明色,它不被显示). 最后,累加器将保存 $1A 的值,它是 $3F18 的镜像. 然后
35、 $1A 不被显示,因为colour #0 为透明色.图形和子图形调色板都被镜像到其他的 VRAM区域; $3F20-3FFF 分别是他们的镜像.被写入 $3F00-3FFF 的 D7-D6 字节被忽略.I. 背景卷轴-NES能够独立于在背景之上的字画面来卷动背景 (pre-rendered Name Table + Pattern Table + AttributeTable). 背景能被水平和竖直卷动.卷轴工作如下:Horizontal Scrolling Vertical Scrolling0 512+-+-+ +-+ 0| | | | | A | B | | A | | | | |+-
36、+-+ +-+| | B | |+-+ 480Name Table “A“ 是通过在寄存器 $2000 中的 Bits D1-D0 来指定的,“B“ 接下来的 Name Table (由于镜15像,这是动态的). 它在同时使用水平和竖直卷轴的游戏时不工作.背景将跨越多个 Name Table,就像这里展示的:+-+-+| Name Table #2 | Name Table #3 | ($2800) | ($2C00) |+-+-+| Name Table #0 | Name Table #1 | ($2000) | ($2400) |+-+-+写到水平卷轴地址为 $2005 的值得范围是 0
37、 至 256.写到垂直卷轴的值是 0-239; 超过 239 的值时不被考虑的 (例如: 248 被认为是 -8).J. 屏幕和子图形的层-在 NES显示的时候使用的是一种特殊的规则:FRONT BACK+-+-+-+-+-+| CI | OBJs 0-63 | BG | OBJs 0-63 | EXT |+-+-+-+-+-+| SPR-RAM | | SPR-RAM | BGPRI=0 | | BGPRI=1 |+-+ +-+CI 的意思是 Colour Intensity 颜色亮度, 与 $2001 的 D7-D5 等价. BG 是 背景 BackGround,EXT是 扩展端口视频信号
38、 EXTension port video signal.BGPRI 描述的是 SPR-RAM 中的 Background Priority 背景优先权 bit,在 per-sprite 基础上 (D5,Byte 2).OBJ 数目描述真正的子图形数目,不是 马赛克索引值 Title Index values.FRONT 被认为是在其他所有层上被看到的 (最后绘制),BACK 被认为是其他所有层之下的 (最先绘制).16K. 子图形和 SPR-RAM-NES支持 64个子图形. 每个子画面的大小可以是 8x8 或者 8x16 像素. 子画面数据被保存在 VRAM 的 Partt-ern Tab
39、le 区域.子画面的特征,比如 flipping 和 优先权,被保存在 SPR-RAM. SPR-RAM 的格式如下:+-+-+-+-+| Sprite #0 | Sprite #1 | . | Sprite #63 |+-+-+-+-+-+-+| | +-+-+-+ Byte | Bits | Description |+-+-+-+| 0 | YYYYYYYY | Y Coordinate - 1. Consider the coor- | | | dinate the upper-left corner of the | | | sprite itself. | 1 | IIIIIIII
40、 | Tile Index # | 2 | vhp000cc | Attributes | | | v = Vertical Flip (1=Flip) | | | h = Horizontal Flip (1=Flip) | | | p = Background Priority | | | 0 = In front | | | 1 = Behind | | | c = Upper two (2) bits of colour | 3 | XXXXXXXX | X Coordinate (upper-left corner) |+-+-+-+Tile Index # 被获得的方法与 Name Table 数据一样.大小为 8x16 的子画面函数有些不同. 一个有偶数 Tile Index # 的 8x16 子画面使用在 VRAM 中 $2000的 Pattern Table; 奇数 Tile Index #s 使用 $1000