7 bit 0
---- ----
Ixxx xxxM MMC5A default power-on read value = $01
| |
| +- In theory but not verified: Read back of mode select (0 = write mode. 1 = read mode.)
+--------- IRQ (0 = No IRQ triggered. 1 = IRQ was triggered.) Reading $5010 acknowledges the IRQ and clears this flag.
Raw PCM ($5011)
7 bit 0
---- ----
WWWW WWWW
|||| ||||
++++-++++- 8-bit PCM data
任地狱MMC5
本文编写以及具体实现中, wiki的'MMC5'页面居然进行了修改(主要是针对BANK切换的说明进行了修正).
MMC5的Mapper编号就是005, 还是有不少的游戏(NesCartDb记录24款, 有美版日版之分). 不过用到MMC5扩展音源的只有:
其中值得一提的是, 金属之光被称为画面最好的FC游戏, 毕竟是可视小说(VN)类型. 其ROM大小是1MB, 在那时肯定是巨无霸水平的.
不过虽然只有少数用了扩展音源, 不过不像VRC7, MMC5没用上的游戏卡带还是拥有相应的硬件(至少FC版).
PRG-RAM
MMC5支持切换RAM-BANK, 这对于目前架构来说又是致命的, 只能再想想. 但是这不是最致命的, 最致命的是信息缺失.
例如《大航海時代》, 数据库中表明其拥有一个电池供电支持的16kb WRAM(SRAM). 一般地, 原始iNES文件头有:
亦或者NES 2.0的文件头:
但是自己手上的大航海時代ROM这两个字节均是0. 也就是说ROM信息不够完整, wiki给出的解决方案是: 假定为64kb大小.
强大的MMC5
MMC5性能非常地强大:
BANK 切换
PRG mode 0:
PRG mode 1:
PRG mode 2:
PRG mode 3:
PRG-BANK 最后一个8kb BANK一定是ROM.
CHR mode 0:
CHR mode 1:
CHR mode 2:
CHR mode 3:
CHR-BANK这里倒是没有什么.
PRG mode ($5100)
大部分游戏使用的是模式3(除了恶魔城3-美版, 用了模式2). 暗荣的游戏从来不写入该寄存器, 可知默认是模式3.
CHR mode ($5101)
金属之光使用的是模式1, 其他的使用的是模式3
PRG RAM Protect 1 ($5102)
D1D0位必须是'10'(2)才能正常写入. 需要结合$5103.
PRG RAM Protect 2 ($5103)
D1D0位必须是'01'(1)才能正常写入. 同样需要结合$5102.
Extended RAM mode ($5104)
ExRAM@$000-$3BF:
ExRAM@$3C0-$3FF:
Nametable mapping ($5105)
MMC5内部实现应该是, 例如模式3, 就根据地址返回填充数据就行. 作为模拟器的话, 可以实现为:
Fill-mode tile ($5106)
8位均用于'填充模式'的图块编号
Fill-mode color ($5107)
低2位用于'填充模式'的属性位, 实际填充的的是:
可以具体平台使用位运算或者查表.
PRG Bank 0, 1, 2 ($5110-5112)
不在PRG空间内, 无效.
PRG Bank 3, RAM Only ($5113)
这个就比较复杂了, 这就是前面提到的信息不完整. 就目前而言有以下几种情况:
D2位表示哪个'chip'. wiki建议始终假设为64kb, 然后根据这4bit(3bit)载入偏移数据, 因为2x8kb模式是写入'100'而不是'001'.
PRG Bank 4, ROM/RAM ($5114)
PRG Bank 5, ROM/RAM ($5115)
PRG Bank 6, ROM/RAM ($5116)
PRG Bank 7, ROM Only ($5117)
似乎启动时是往$5117写入$FF, 也就是最后8kb RPG-BANK载入最后一个BANK.
CHR Bankswitching ($5120-$5130)
前面提到了MMC5的'黑科技'——8x16精灵使用的图样表允许和背景使用的不同. 8x8模式只会使用$5120-$5127, 而8x16模式下$5120-$5127是针对精灵, $5128-$512B是针对背景.
并且, 最后一次写入的部分(前8, 后4), 会用于 PPUDATA ($2007)
wiki提到到目前未知还不清楚MMC5是怎么检测PPU处于哪种模式的, 真的'黑科技'.
根据$5130的说法, 比如8kb模式就是选择的是8kb为窗口的BANK编号.
Upper CHR Bank bits ($5130)
当使用1kb模式时, 最多只能访问256kb的CHR-ROM, 要访问整个1024kb就需要这两位了. 不过唯一一个超过256kb CHR-ROM的金属之光却使用的是4kb模式. 换句话说就是没有一个游戏使用了这个机能(甚至连初始化都没有).
Expansion RAM ($5C00-$5FFF, read/write)
模式1下( ExGrafix 模式), 就是MMC5实现的一个难点了: 扩展RAM区每个字节可以用来强化背景显示.
4*64=256
, 为了使用整个1024kb空间, 需要配合$5130的两位进行使用.这种模式下基本可以确定使用的是单屏模式下. 举个栗子, 第一个图块$2000. 原本的模式下, 首先确定背景是用的哪个图样表, 然后利用[$2000]的数据, 获取图样数据.
现在ExGrafix模式下, 会在ExRAM:$000获取相应信息, 而本来的图样表几乎完全是为精灵服务的.
高精度的模拟器应该是模拟读取过程, 不过作为中精度的模拟器可以直接拿渲染开刀.
Split模式相关寄存器
待补充
目前只有宇宙警备队 SDF使用了该模式, 这个模式目前不想实现(懒), 等待以后实现吧.
IRQ Counter ($5203)
用于指定扫描线id来触发IRQ, 内部比如写入$04会在第5条可见扫描线开始时触发. 写入0应该是触发不了IRQ的. 由于是基于扫描线的, 所以应该只会在可见扫描线触发相关同步操作.
目前的Ez模式下, 本身自己是在每条扫描线最后触发水平同步的, 所以就是应该写入多少就在第几条触发.
IRQ Status ($5204, write)
写入仅仅用来启用/关闭IRQ功能, 即时关闭也能在本来可以触发IRQ情况将'Pending'置为1(当然不会触发IRQ).
IRQ Status ($5204, read)
'In Frame'是当MMC5不再检测到扫描线信号时, 比如最后一根扫描线扫过, 或者说PPU没有渲染背景/精灵($2001相关位). 也就是说实际上如果中途关闭渲染, 会提前清除'In Frame'标志(懒得实现).
'Pending'标志会在MMC5的相关IRQ挂起时触发, 读取后清除(确认IRQ), 或者在'In Frame'0->1时也会清除.
Unsigned 8x8 to 16 Multiplier ($5205, $5206 read/write)
这就是那个16位乘法器了, 写入会进行乘法运算. 读取时, 低地址读取地址, 高地址读取高地址.
其他寄存器
其他还有一些就不介绍了
switch-case
由于地址部分连续, 部分离散, 所以只好直接用case了, 让编译器自己优化.
新接口
read_low
, 读取[$4020, $6000), 这部分区域会调用该接口. 在正常情况下, 与之前的PRG段快速访问优化不冲突.区别ROM RAM
目前是使用的32bit整型保存偏移量, 但是没有办法区别BANK是来自ROM还是RAM. 所以现在统一用最高位区别RAM与ROM.
之前的文件头"-StepFC-SRAMWRAM"完全没有必要, 但是看着文件管理器显示9kb有点烦, 干脆去掉了. 完全根据大小信息判断:
模拟大航海时代出现的问题
由于使用了MMC5-ExGrafix模式, 这个背景显示老是有问题. 以为是ExGrafix模式实现有问题, 结果发现是因为很久没碰渲染层导致逻辑忘了.
目前的实现每个像素有效位为低5位: [xxxA BCDE], 其中E是判断是否为全局背景:
E = C | D
, CD是图样的低两位, AB是属性位, 自己还以为是[xxxx ABCD]模式.MMC5 扩展音源
MMC5的扩展音源相对其他来讲很简单——因为实际上已经实现过了: 和2A03的相关声道几乎一致. 对比起VRC6来, 没有锯齿波也罢了, 方波还没有什么特色.
所以在NSF创作者看来, MMC5扩展音源毫无特色. 用上MMC5基本上意味着已经没有其他扩展音源的可用了——MMC5仅仅是陪衬品.
Pulse 1 ($5000-$5003)
与2A03的方波区别:
Pulse 2 ($5004-$5007)
第二个方波, 同上, 由于没有扫描单元, 完全一致(2A03的两个方波在扫描上有所区别——反码与补码).
PCM Mode/IRQ ($5010) Write
PCM Mode/IRQ ($5010) Read
Raw PCM ($5011)
读取模式会忽略缩写内容, 写入$00不会影响输出(PCM值可能为0啊, 需不需要实现?)
PCM IRQ
有兴趣的可以自行了解.
Status ($5015, read/write)
类似$4015, 只有最低两位使用了.
模拟金属之光出现的问题
MMC5音源
一开始, 金属之光使用MMC5的二号方波, 用于播放文字'哔哔哔'的音效. 但是似乎希望, 通过往$5004写入$00来静音方波. 找了很久, 甚至一行一行对照其他模拟器的实现, 的确写入$00不能静音!
似乎陷入僵局, 又只好一步一步反汇编, 发现是通过读取$5DD5的数据写入$5004的, 所以结果是ExRAM实现有问题而不是方波!
之前不小心实现为:
金属之光使用的是模式2——ExRAM模式, 让所有数据写入0了, 应该实现为:
MMC5图像
金属之光虽然写入了两段CHR-BANK切换用寄存器, 也使用了8x16精灵模式, 也就是说使用了'黑科技'. 但是目前来看(时间原因, 主要是没有汉化玩不下去), 两段CHR-BANK切换写入的内容是一样的, 也就是实际上没有利用这一机能.
简单来说有两个问题:
return
了.第一个BUG目前来说不可能修改, 原因是因为储存的是调色板索引, 不能表示'黑色'. 第二个BUG和之前的IRQ中切换BANK一样, 有两种解决方案:
目前来看, 这两种解决方案的选择应该是: 两个都要(我全都要)! 可以用来解决目前渲染的3个已知BUG, 交给后面完成吧(懒)!
简单汇总
MMC5近乎20款游戏中, 这里仅仅测试了两款——大航海时代与金属之光.
大航海时代使用了ExGrafix模式, 但是仅仅是方便程序猿进行场景布置, 而没有渲染出令人信服的画面.
金属之光: MMC5的三个图像加强的功能, 金属之光实际都没用上(大概), MMC5的额外音源也仅仅用来放文字'哔哔'音效(大概). 可以看出这游戏似乎一开始可能并没有打算使用MMC5.
总的来说MMC5是一款非常强大的MMC, 导致模拟器大幅度地进行调整, 甚至在渲染层打洞来支持MMC5特性. 由于精力原因目前还没有完全模拟: Split模式与'黑科技'模式没有实现, 打上'TODO'等待以后慢慢补上.
(RAM写入保护也没有实现, 填充模式实现了, 但似乎没用过导致没法测试)
REF