7 bit 0
---- ----
BBBB BBBB
|||| ||||
++++-++++- The bank number to select for the specified bank.
8个就是1kb的BANK. 注意防止溢出的操作.
命令: PRG Bank 0 ($8)
7 bit 0
---- ----
ERbB BBBB
|||| ||||
||++-++++- The bank number to select at CPU $6000 - $7FFF
|+------- RAM / ROM Select Bit
| 0 = PRG ROM
| 1 = PRG RAM
+-------- RAM Enable Bit (6264 +CE line)
0 = PRG RAM Disabled
1 = PRG RAM Enabled
Sunsoft FME-7
其实FME-7并不是NSF扩展音源所支持的芯片名称, 而是其变种——Sunsoft 5B. Sunsoft FMT-7, 5A以及5B共用一个Mapper编号——69. 由于格式原因, 程序中FME7代指Mapper069, 包括(甚至特指)Sunsoft 5B, 但是其实FME7是5B的子集.
Sun电子
比起其他厂商, 例如NSF就有提到的科乐美, 任天堂以及南梦宫. Sun电子似乎进入21世纪后就逐渐淡出游戏和行业了. 翻了一下发行游戏列表, 近10年就发行了几款, 不过似乎在吃老本——还有当初FC很好玩的《超惑星战记》的续作.
Sun电子在FC时代出了很多不错的作品, 但其实在这里都不重要, 重要的其编曲水平之高. 例如仅仅使用2A03的《RAF世界》, 这样一个高编曲水平的开发商的Sunsoft 5B又如何呢?
吉米克!
《Gimmick!》, 感觉和 拉格朗日点 很相似——唯一一个使用了独立扩展音源的游戏, 一个是VRC7, 一个是5B.
但是其实 吉米克! 也没有完全了利用5B的机能——没有使用到噪音发生器和包络发生器.
FME7总览
wiki介绍FME7支持到512kb的PRG-RAM, 这是目前来看最多的PRG-RAM, 但是自己一个一个看了目前的游戏列表, 最多的也就是8kb的WRAM.
对于PRG-RAM来说, 目前还是直接声明在结构里面, 直接增加512k的PRG-RAM感觉没有什么必要. 如果真的需要实现, 这部分最好使用动态申请, 然后ROM-RAM区分需要从1bit提高到2bit用来区分这部分的RAM(并且, 目前没有一些游戏内运行时错误的处理, 可能需要使用
long_jmp
).寄存器
FME7与其他的MMC有所不同的是, 先将命令写入命令寄存器($8000-9FFF), 再把参数写入参数寄存器($A000-BFFF).
命令: CHR Bank 0-7 ($0-7)
8个就是1kb的BANK. 注意防止溢出的操作.
命令: PRG Bank 0 ($8)
支持切换512kb的ROM/RAM. 之前提到了, 最多的就是使用了8kb的WRAM. ROM方面, 其实还是没有游戏真正利用可以切换ROM-BANK. 不过现在没有实现写入保护, 切换到ROM再写入的话有点危险.
命令: PRG Bank 1-3 ($9-B)
用于切换$8000-$9FFF, $A000-$BFFF, $C000-$DFFF的BANK. 注意防止溢出的操作.
命令: Name Table Mirroring ($C)
中规中矩没什么可以说, 自己目前的是[2,3,0,1]的顺序, 可以用
[2,3,0,1][mode]
查表外, 自然就是mode XOR 2
就行了.命令: IRQ Control ($D)
FME7的IRQ是通过一个16bit的计数器, D7启动时会在每个CPU周期递减. 当D0启动并且计数器从$0000变成$FFFF触发IRQ.
写入该命令以确认IRQ.
命令: IRQ Counter Low Byte ($E)
IRQ计数器的低8位
命令: IRQ Counter High Byte ($F)
IRQ计数器的高8位
模拟蝙蝠侠出现的问题
Sun电子出品的《蝙蝠侠》难度比较高, 反正小时候没通关就是了, 还是老问题, 让蝙蝠侠变成字母侠了:
游戏问题
有2个问题, 模拟出现问题(瑕疵), 但是使用其他模拟器也是同样的:
5B扩展音源
FME7写入高地址有两个空缺的位置, 就是为音频准备的. 硬件方面是Yamaha YM2149F(出现了, 又是雅马哈)的一种.
Audio Register Select ($C000-$DFFF)
Audio Register Write ($E000-$FFFF)
YM2149F 内部寄存器
$07音调/噪声禁用位:
声音
一共拥有3个声道输出方波, 当然还有一个噪音发生器与包络发生器, 允许这三个声道使用.
5B通过CPU驱动, 不过YM2149F和APU类似, 内部有一个分频器可以让频率降低一半. 而 吉米克! 正是使用了这个模式.
与其他芯片声道对比, 5B的周期就是真正的周期, 不用+1s, 周期0似乎同周期1等价.
声调
声调发生器用来产生方波:
Frequency = Clock / (2 * 16 * Period)
Period = Clock / (2 * 16 * Frequency)
方波(square), 之前的2A03也提到, 真正的应该叫做脉冲波(pulse), 其中50%占空比的称为方波. 由于wiki整篇没有提到占空比, 所以5B发出的应该就是真正的方波. 其中, 方波的01的'交替频率'自然是上面的两倍.
如果包络使能位设为1, 音量由包络控制, 否则输出自身的音量.
噪音
噪音发生器利用$06通过的5bit周期生成一个1bit的随机波.
Frequency = Clock / (2 * 16 * Period)
Period = Clock / (2 * 16 * Frequency)
包络频率
包络的每一个斜面(ramp)的频率如下:
Frequency = Clock / (2 * 256 * Period)
Period = Clock / (2 * 256 * Frequency)
每个Ramp又被细分成32步, 对应的就是'音量'的改变.
左边部分就是对应的固定音量. 右边部分则是包络使用的, 可以看出:
也就是可以用两个LUT, 反正要用, 不差这一个.
包络形状
通过写入$0D能够重置包络, 然后从4个参数选择其形状:
(注: 图表中斜面的'斜率'是1)
也就是可以利用$08或者$0C模拟锯齿波, $0A或者$0E模拟三角波(不过前面了解到, 其实是指数版的锯齿波与三角波).
具体实现中, 希望体现出'形状', 于是这样实现: 化为4步, 然后执行12343434...
形状则是:
还可以使用大号的两级LUT(
uint8_t[16*64] + uint16_t[32]
), 或更大号的1级LUT(uint16_t[16*64]
).不过桌面平台应该是自己这种实现要快一点(缓存友好).
输出
可以看出难点仅仅在于包络发生器的模拟, 其他的非常简单.
还能够简化, 但是不想动脑筋了.
音量
模拟器吉米克出现的问题
这个很恼火.
开始一切正常, 但是进入游戏就一上来就死. 一步一步追踪, 老是以为IRQ实现有问题(为什么自己老是以为是IRQ有问题???).
然后发现CPU$173储存了数据, 但是老为0. 一步一步发现读取了WRAM区域, 吉米克! 将ROM切换到这里了. 最后的最后发现是把 PRG Bank 0 ($8) 的RAM/ROM位看反了:
看成了
...
最后, 自然还有老BUG(游戏状态栏一部分用精灵拼的). 看来FC游戏都喜欢在IRQ中切换BANK.
REF
附录: 查询表生成
自己用的LUT生成如下:
附录: 相关音色简单探索
这里简单测试了一下 吉米克! 没有使用过的包络、噪音的音色.
噪音, 将噪音和方波的周期弄到最大.
包络, 由于使用包络后不能调整音量了, 只能调整频率, 和2A03的三角波差不多.
听起来像......噪音..? 不好意思, 声音开得太大了