CPU $8000-$BFFF: 16 KB switchable PRG ROM bank
CPU $C000-$DFFF: 8 KB switchable PRG ROM bank
CPU $E000-$FFFF: 8 KB PRG ROM bank, fixed to the last bank
CHR $0000-$03FF: 1 KB switchable CHR ROM bank
CHR $0400-$07FF: 1 KB switchable CHR ROM bank
CHR $0800-$0BFF: 1 KB switchable CHR ROM bank
CHR $0C00-$0FFF: 1 KB switchable CHR ROM bank
CHR $1000-$13FF: 1 KB switchable CHR ROM bank
CHR $1400-$17FF: 1 KB switchable CHR ROM bank
CHR $1800-$1BFF: 1 KB switchable CHR ROM bank
CHR $1C00-$1FFF: 1 KB switchable CHR ROM bank
7 bit 0
---------
.... PPPP
||||
++++- Select 16 KB PRG ROM at $8000
16*16=256
8k PRG Select ($C000-$C003)
7 bit 0
---------
...P PPPP
| ||||
+-++++- Select 8 KB PRG ROM at $C000
8*32=256
PPU Banking Style ($B003)
7 bit 0
---------
W.PN MMDD
| || ||||
| || ||++- PPU banking mode; see below
| || ++--- Mirroring varies by banking mode, see below
| |+------ 1: Nametables come from CHRROM, 0: Nametables come from CIRAM
| +------- CHR A10 is 1: subject to further rules 0: according to the latched value
+--------- PRG RAM enable
7 bit 0
---- ----
.... .ABH
|||
||+- Halt
|+-- 16x frequency (4 octaves up)
+--- 256x frequency (8 octaves up)
H - halts all oscillators, stopping them in their current state
B - 16x frequency, all oscillators (4 octave increase)
A - 256x frequency, all oscillators (8 octave increase)
可乐妹的VRC6
那就从NSF的扩展音源最低位开始吧, VRC6有两个变种:
当然所述为日版(FC), NES版由于老任的策略不能使用自己搭载扩展音源的卡带.
BANK
感觉设计很科学, PRG-ROM方面16kb切换, 8kb切换, 8kb固定. CHR-ROM全是1kb可切换
PRG-ROM支持到256kb, CHR-ROM也是.
寄存器
由于地址线只有0,1,12-15可用, 镜像地址可以用: 与
$F003
做与运算获得($DE6A -> $D002
).同时两个变种的区别就是: 地址线A0,A1是相反的.
换句话说, MAPPER-026实现可以为:
16k PRG Select ($8000-$8003)
16*16=256
8k PRG Select ($C000-$C003)
8*32=256
PPU Banking Style ($B003)
CIRAM (Console-Internal RAM, FC内部自带的RAM). 是的! VRC6支持用ROM代替RAM.
现有的游戏只有这几种情况:
$20, $24, $28, $2C, $A0, $A4, $A8, $AC
.CHR Select 0…7 ($Dxxx, $Exxx)
为了方便描述, 将
$D000-$D003, $E000-$E003
依次描述为R0-R7.$B003
的第三位影响CHR-ROM的切换:图样表:
[$B003] & $03
名称表:
[$B003] & $07
之前提到名称表拥有大致三种模式: 水平镜像、垂直镜像以及四屏模式. 但是实际上还有更多的模式, 比如三屏、一屏. 详细的还是查看引用链接.
图样表还行, 名称表解释起来太麻烦了, 直接上代码(没有考虑切换名称表切换CHR-ROM):
IRQ control ($F00x)
VRC系列的IRQ是相同的逻辑, 与其他IRQ系统不同的是, VRC IRQ是基于CPU周期的. 自然, 即便是禁用PPU渲染, 或者VBlank时, 也能触发IRQ.
当然主要功能还是模拟扫描线(切换模式)
$F002
确认IRQ中有一个重要的操作E=A
而不是E|=A
, 千万不要像自己以为身经百战见得多了, 东边哪个IRQ没有见过? 找了非常长时间的BUG.扫描线模式, 每根扫描线输出一个时钟信号. 通过将CPU周期除以[114, 114, 113], 然后重复序列. 所以可以认为是除以113.667(NTSC的场合, PAL需要调整至106又16分之5). 不过, 由于目前的架构是基于扫描线进行水平同步的, 所以是反过来的.
(CPU)周期模式, 每个(CPU)时钟周期输出一个信号. 感觉太夸张了, 毕竟一个指令最少也要花2周期, 不知道是不是自己理解错了.
当输出一个时钟信号时:
当然IRQ被禁止的话什么都不会干.
VRC6 扩展声部
这部分才是本篇的本体! 很多NSF作者很喜欢VRC6, 原因是增加两个方波和一个锯齿波, 得到了加强但是又不至于太过分.
由于NSF的存在, 自己将音频数据放在了核心部分, 而不是依靠Mapper保存.
Frequency Control ($9003)
那三个游戏都没有使用这个这个寄存器, 仅仅是简单
=0
. 考虑不用支持?Pulse Control ($9000,$A000)
Saw Accum Rate ($B000)
Freq Low ($9001,$A001,$B001)
Freq High ($9002,$A002,$B002)
方波
VRC6的方波与2A03自带的方波类似.
M=1
时, 持续输出当前音量, 也就是可以认为是[1, 1, ...., 1]
通过
E=0
, 会复位占空比索引并停止, 输出0. 通过E=1
, 会从头恢复.虽然占空比序列长度是16, 为2A03的2倍. 但是由于是CPU频率驱动的, 所以计算公式还是一致的:
具体实现可以考虑像2A03的矩形波一样进行查表, 不过太有规律了, 可以用
i <= d
进行判断.这里简单实现为:
锯齿波
这算是一个新东西, 不过和三角波相似, 甚至在函数表述上比三角波还简单.
同样是CPU周期驱动的12bit周期数据. 每两次由周期输出时钟时, 内部的8bit累加器加上
[$B000]:A
, 每次则输出高5bit. 第七次重置归零:如果A大于42, 会导致8bit数据溢出从而让声音失真. 通过写入
E=0
累加器会复位到下次E=1
. 频率计算公式为:这里简单实现为:
输出
就连wiki上面介绍VRC6输出的口吻也是比较含糊的, 主要有两点:
根据之前DAC中给出的线性逼近的公式:
pulse_out = 0.00752 * (pulse1 + pulse2)
, 可知线性因子大概是0.00752
, 由于不太确定, 可以根据情况上下浮动.要点
E: 0 -> 1
时, 重置索引/累加器状态恶魔城传说模拟出现的问题
(红框处应该有一个蝙蝠状敌人)
同之前的MetalMax, 由于目前精灵是在最后一起渲染的, 导致中途切换BANK会让精灵使用错误的图样表BANK渲染
还有一个小问题就是, 这个画面中, 背景会来回1像素上下跳动, 这个应该是IRQ精度问题
REF