dustpg / BlogFM

Blog for Me
MIT License
155 stars 23 forks source link

Re: 从零开始的红白机模拟 - [20]Mapper 004 #24

Open dustpg opened 6 years ago

dustpg commented 6 years ago

STEP⑨: 实现部分Mapper

接下来进入本次的主角 Mapper004:

Mapper004: MMC3 - TxROM

MMC3 可谓是最开始几个Mapper中相当占分量的Mapper. MMC3是少数可以触发IRQ的Mapper之一.

MMC6也是用同一个mapper编号, 内部逻辑大致相同.

根据数据库,MMC3(在自己看来)比较有名的游戏, 比如:

MMC3的IRQ最大的用处, 就是处理的分割滚动效果(状态栏在下面)

IRQ 与 NMI区别

Banks

寄存器

MMC3根据地址拥有4对寄存器

Bank select ($8000-$9FFE, 偶数)

7  bit  0
---- ----
CPMx xRRR
|||   |||
|||   +++- Specify which bank register to update on next write to Bank Data register
|||        0: Select 2 KB CHR bank at PPU $0000-$07FF (or $1000-$17FF);
|||        1: Select 2 KB CHR bank at PPU $0800-$0FFF (or $1800-$1FFF);
|||        2: Select 1 KB CHR bank at PPU $1000-$13FF (or $0000-$03FF);
|||        3: Select 1 KB CHR bank at PPU $1400-$17FF (or $0400-$07FF);
|||        4: Select 1 KB CHR bank at PPU $1800-$1BFF (or $0800-$0BFF);
|||        5: Select 1 KB CHR bank at PPU $1C00-$1FFF (or $0C00-$0FFF);
|||        6: Select 8 KB PRG ROM bank at $8000-$9FFF (or $C000-$DFFF);
|||        7: Select 8 KB PRG ROM bank at $A000-$BFFF
||+------- Nothing on the MMC3, see MMC6
|+-------- PRG ROM bank mode (0: $8000-$9FFF swappable,
|                                $C000-$DFFF fixed to second-last bank;
|                             1: $C000-$DFFF swappable,
|                                $8000-$9FFF fixed to second-last bank)
+--------- CHR A12 inversion (0: two 2 KB banks at $0000-$0FFF,
                                 four 1 KB banks at $1000-$1FFF;
                              1: two 2 KB banks at $1000-$1FFF,
                                 four 1 KB banks at $0000-$0FFF)

MMC6 的M位是指是否使用PRG-RAM.

nesdev给出了详细的情况列表, 可以自行查看, 编码时直接抄就行了

Bank data ($8001-$9FFF, 奇数)

7  bit  0
---- ----
DDDD DDDD
|||| ||||
++++-++++- New bank value, based on last value written to Bank select register (mentioned above)

Mirroring ($A000-$BFFE, 偶数)

7  bit  0
---- ----
xxxx xxxM
        |
        +- Nametable mirroring (0: vertical; 1: horizontal)

这个就很简单了

PRG RAM protect ($A001-$BFFF, 奇数)

7  bit  0
---- ----
RWXX xxxx
||||
||++------ Nothing on the MMC3, see MMC6
|+-------- Write protection (0: allow writes; 1: deny writes)
+--------- PRG RAM chip enable (0: disable; 1: enable)

PRG RAM保护..感觉没必要实现

IRQ latch ($C000-$DFFE, 偶数)

IRQ了, 很重要的一环

7  bit  0
---- ----
DDDD DDDD
|||| ||||
++++-++++- IRQ latch value

IRQ闩锁, 用于指定一个重载值. 当计数器归零后, 计数器会重载这个值. 这个值会在每根扫描减少, 降至0就触发IRQ.

由于内部的原理是通过PPU巴拉巴拉, 所以要在背景精灵启动渲染才会触发倒计时, 否则运行超级马里奥3会程序会挂掉.

IRQ reload ($C001-$DFFF, 奇数)

IRQ重载, 写入任意值会让计数器归0

IRQ disable ($E000-$FFFE, 偶数)

IRQ禁止, 写入任意值标记禁止并且确认挂起的中断

IRQ enable ($E001-$FFFF, 奇数)

IRQ使能, 写入任意值标记使能

Mapper接口: 水平同步

这次功能就需要新的一个接口, 需要在每条扫描行进行一次同步, 我们就把它叫水平同步好了

// 水平同步
void(*hsync)(sfc_famicom_t*);

由于目前的是EZ模式, 我们在每次可见扫描线结束后进行一次同步, 即水平同步. 计数器减到0就触发一次IRQ.

关于IRQ触发更为详细的细节请查看原文.

实现

本次的实现比较重要, 也明显比前面几个代码量更大.

STEP9-MAPPER004.c

结束?

本次先介绍的4种mapper就介绍完毕

项目地址Github-StepFC-Step9

作业

双截龙2: 复仇 模拟出现的问题

重装机兵模拟出现的问题

REF