首页 > 其他分享 >童年神机小霸王(七) Mapper

童年神机小霸王(七) Mapper

时间:2023-12-23 22:31:30浏览次数:40  
标签:Mapper 神机 映射 mapper 寄存器 PRG CHR 小霸王 bank

Mapper

mapper,这个概念来源于 memory mapping,又叫做 Memory Management Circuit,它是解决地址映射的一种电路,简单来说就是决定物理内存如何映射到 CPU 或者 PPU 的地址空间

mapper 可以用来支持增加卡带的 RAM 甚至支持额外的音频通道,但更一般的目的就是控制物理内存到地址空间的映射,突破游戏 40KB 的限制

为什么说是 40KB 的限制,因为早期一般的游戏最大就是 童年神机小霸王(七) Mapper_c++ 的 PRG,以及 童年神机小霸王(七) Mapper_寄存器_02

mapper 的种类太多太多,不同 NES 版本的 mapper 也有所不同,各种杂七杂八的加起来有好几百个,不过这里我们挑几个常见的游戏使用的 mapper 来说明。

NROM

mapper 000,排在第零个,最简单的一种 mapper,像超级马里奥就使用的是 NROM。NROM 也分种类,NROM-128 的存放 PRG 的 ROM(后面简称 PRG-ROM) 只有 16KB,而 NROM-256 有 256KB。

  • PRG 的第一个 bank(16KB) 映射到 0x8000-0xBFFF,最后一个 bank 映射到 0xC000-0xFFFF。
  • PPU 的 VRAM 开头 8KB 映射到 CHR,也就是 PatternTable

这就是最简单的 NROM,与我们前面讲述 CPU 和 PPU 时一致,当时不是说不讨论复杂情况吗,其实就是在用 NROM 来举例子。

MMC1

mapper 001,使用 MMC1 的游戏有双截龙,恶魔城等,来看其 bank 和映射关系:

  • CPU 0x6000-0x7FFF 映射到 8KB 的 PRG RAM bank,这是可选的
  • CPU 0x8000-0xBFFF 映射到 PRG ROM 的一个 bank,这个 bank 要么是可切换的要么固定为第一个
  • CPU 0xC000-0xFFFF 映射到 PRG ROM 的一个 bank,这个 bank 要么是可切换的要么固定为最后一个
  • PPU 0x0000-0x0FFF 映射到一个 4KB 可切换的 CHR bank
  • PPU 0x1000-0x1FFF 映射到一个 4KB 可切换的 CHR bank

MMC1 这个 mapper 就高级多了,它有一系列的端口寄存器,我们可以操作这些端口来配置 MMC1。来简单看看有哪些端口:

Control

0x8000-0x9FFF,向这部分地址空间任意一地址写入数据都会写入寄存器 0,有朋友可能会有疑问,这部分地址空间不是映射到 PRG 吗,怎么又与一个寄存器相连了?虽然我不清楚具体电路,但是不难推断这是没问题的,PRG 程序代码是只读的,但这里是写入。很多地方端口相同但读写不同的情况下,映射可能也有所不同,比如前面我讲述串口时其中很多的端口就是这样子的,所以这里是不冲突没有问题的,接着来看 0x8000-0x9FFF 这部分地址空间表示的端口:

  • bit0:0 表示设置为 horizontal 镜像,1 表示设置为 vertical 镜像
  • bit1:0 表示设置为 single 镜像
  • bit2:0 表示 bank switching 发生在 0xC000-0xFFFF,1 表示 bank switching 发生在 0x8000-0xBFFF
  • bit3:0 表示 bank 大小为 32KB,也就是一次性交换 32KB(0x8000-0xFFFF),1 表示按照 bit2 的设置来交换
  • bit4:0 表示一次性交换 8KB 的 CHR,1 表示交换 2 个分开的 4KB CHR banks
  • bit7:置 1 表示清空这个寄存器

这里说明一下这个 bank 没有特定的大小,都是根据硬件设置而来,而且 PRG CHR 等都用 bank 来做交换的基本单位,可能有些混淆这里说明一下。

CHR bank 0

0xA000-0xBFFF,这部分地址空间连接到了另一个端口,向这个端口写入 CHR bank number 可以选择 CHR 的那一块 bank 映射到 PPU 的 0x0000-0x0FFF,如果 CHR bank 的大小在 Control 寄存器设置为 8KB,那么就会选择一个 bank 映射到 0x0000-0x1FFF。

CHR bank 1

0xC000-0xDFFF,道理同上,向这部分地址空间任意一地址写入 CHR bank number 可以将选择的 bank 映射到 PPU 的 0x1000-0x1FFF

PRG bank

0xE000-0xFFFF,同理,写入 PRG bank number 来选取一个 PRG bank,至于这个 bank 多大,映射到 CPU 地址空间中的 0x8000 处还是 0xC000 处要视 Control 寄存器的设置决定。

UNROM

下面接着来看 mapper 002,使用这个 mapper 的著名游戏有魂斗罗,洛克人等等。UNROM 比较厉害,最高可支持 4M 的 PRG,要知道 M 这个单位在那时对游戏来说是个很大的单位了。虽然 UNROM 可以支持 4M 的大容量 PRG,但其实 UNROM 还没 MMC1 复杂,来看其 banks 的规划(映射关系)

  • CPU 0x8000-0xBFFF,16KB 可切换的 PRG ROM bank
  • CPU 0xCFFF-0xFFFF,16KB 固定的 PRG ROM bank,这部分地址空间固定映射到最后一块 PRG bank
  • CHR 容量 8KB,就映射到 PPU 开头的 2KB

就只有这些,还是挺简单的,UNROM 只支持 2 种镜像垂直和水平,而且设置方式是制作卡带时就焊接好的(solder pad,如果我没理解错的话),它有一个 bank 选择寄存器,向 0x8000-0xFFFF 这部分地址空间的任一地址写入 PRG bank number 即可选择一 PRG bank 映射到 0x8000

不知道细心看的朋友有没有一个疑惑,像魂斗罗,洛克人这类的游戏都是打游戏,特别是魂斗罗,我之前讲述的文章里面包括了很多魂斗罗的例子,CHR 容量 8K 够用吗?显然所有的图案表加起来肯定超过 2 个也就 8KB。

像魂斗罗这类的游戏有些特殊啊,它们没有 CHR ROM,有的是 CHR RAM(可以将 PPU 的开头 8KB 视作 CHR RAM),通过 FCEUX 可以知道魂斗罗的 PRG ROM 为 128KB,没有 CHR ROM,它的 PatternTable 就在 PRG 里面,是游戏运行期间 CPU 控制通过 PPU 端口将 PatternTable 从 PRG 复制到 CHR RAM

CNROM

mapper003 CNROM,这个 mapper 也比较简单,较为出名的游戏有勇者斗恶龙,高桥名人的冒险岛等等,前面关于 mapper 都写得差不多,应该有这概念了,后面我就简述了

banks

  • PRG ROM 只有 16KB 或者 32KB,跟 mapper 000 一样,不可 bank switching
  • CHR ROM 较大,up to 2M,CHR bank size 为 8KB,CHR banks 之间切换,映射到 PPU 的 0x0000-0x1FFF

register

register 只有一个,类似 UNROM,向 0x8000-0xFFFF 这部分地址空间的任一地址写入 CHR bank number 即可选择一 CHR bank 映射到 0x0000-0x1FFF

MMC3

mapper004 MMC3,使用 MMC3 的游戏很多很多,较为出名的我比较喜欢的有热血系列比如说热血格斗传说,热血物语等等。

Banks

MMC3 对于 banks 的规划就很精细,很多,意思也大同小异,我就不重复写了,直接看 wiki 上的资料:

  • CPU 0x6000-0x7FFF: 8 KB PRG RAM bank (optional)
  • CPU 0x8000-0x9FFF (or 0xC000-0xDFFF): 8 KB switchable PRG ROM bank
  • CPU 0xA000-0xBFFF: 8 KB switchable PRG ROM bank
  • CPU 0xC000-0xDFFF (or 0x8000-0x9FFF): 8 KB PRG ROM bank, fixed to the second-last bank
  • CPU 0xE000-0xFFFF: 8 KB PRG ROM bank, fixed to the last bank
  • PPU 0x0000-0x07FF (or 0x1000-0x17FF): 2 KB switchable CHR bank
  • PPU 0x0800-0x0FFF (or 0x1800-0x1FFF): 2 KB switchable CHR bank
  • PPU 0x1000-0x13FF (or 0x0000-0x03FF): 1 KB switchable CHR bank
  • PPU 0x1400-0x17FF (or 0x0400-0x07FF): 1 KB switchable CHR bank
  • PPU 0x1800-0x1BFF (or 0x0800-0x0BFF): 1 KB switchable CHR bank
  • PPU 0x1C00-0x1FFF (or 0x0C00-0x0FFF): 1 KB switchable CHR bank

Registers

I Bank Select

0x8000-0x9FFE,这之间的偶数地址连接到 Bank Select 寄存器,顾名思义,写入这个寄存器可以控制映射方式,具体如下,我还是直接贴 wiki 的资料:

童年神机小霸王(七) Mapper_c++_03

只用关注前面几位就行,不同的 RRR 映射方式不同,上图写得很清楚了,我就不再多做解释。

II Bank Data

0x8001-0x9FFF,这之间的奇数地址连接到 Bank Data 寄存器,就是向这个寄存器写入 bank number 来选取一个 bank 然后然后按照 Bank Select 寄存器中的方式映射。

III Mirroring

0xA000-0xBFFE,这之间的偶数地址连接到 Mirroring 寄存器,这个寄存器的 bit0 为 0 的话表示 垂直镜像,为 1 的话表示 水平镜像

IV PRG RAM

0xA001-0xBFFF 奇数部分地址连接到此寄存器,这个寄存器的 bit7 可以使能 PRG RAM(0x6000-0x7FFF),简而言之可以允许你存档了。

MMC3 是允许产生 IRQ 中断的,前面说了 CPU 有三种中断,RESET,NMI,IRQ,前两种的来源都说过,而 IRQ 的中断源就来自这的 mapper,与之相关的有 4 个寄存器:

V IRQ Latch

0xC000-0xDFFE 偶数部分,这个寄存器里面存放着 IRQ 计数器开始计数的数字

VI IRQ reload

0xC000-0xDFFF 奇数部分,向这个寄存器写入任何数据都会使得 IRQ Latch 中存放的数重新加载到内部的计数器

VII IRQ disable

0xE000-0xFFFE 偶数部分,向这个寄存器写入任何数据都会禁止 IRQ 产生

VIII IRQ enable

0xE001-0xFFFF 奇数部分,向这个寄存器写入任何数据都会使能 IRQ 产生

至于产生中断后干什么,那就看 IRQ 的中断处理程序,mapper 产生的 IRQ 可以用来屏幕分割,之前不是说了可以利用 sprite 0 hit 来判断 scanline 的渲染情况,渲染到那儿了,这里也可以用 IRQ,这也是 IRQ 最主要的作用。

好了,上述就是 mapper 的一些内容,更多详情有兴趣的还是请看 wiki 上的资料。到此,结合之前讲述的所有内容,应该对 NES 的 PRG,CHR,mapper,CPU,PPU 之间是如何配合使得游戏运行起来有一个大致的认识了。

本文就到这里了,有什么问题还请批评指正,也欢迎大家来同我交流学习。

标签:Mapper,神机,映射,mapper,寄存器,PRG,CHR,小霸王,bank
From: https://blog.51cto.com/u_15193561/8947278

相关文章

  • Pix4Dmapper空间三维模型的应用实例:GIS选址分析
      本文介绍基于无人机影像建模完成后的结果,利用ArcMap软件进行空间选址分析,从而实现空间三维模型应用的方法。目录1空间分析目标确立2基于基本约束条件的选址求解2.1坡度计算与提取2.2海拔提取2.3LAS数据初探2.4淹没分析2.5区域相交2.6面积约束3基于择优条件的选址求......
  • 第四章:mapper映射文件存放位置、springboot支持事务
    一、mapper映射文件存放位置二、springboot支持事务......
  • Mapper.xml
    <resultMapid="resuleMap"type="com.com.entity.xxx"><idproperty="id"column="id"></id><resultproperty="xxx"column="xxx"></result ><resultproperty=&qu......
  • SpringBoot+MyBatis-Plus没有扫描到Mapper的问题
    一、问题:WARN22052---[      main]ConfigServletWebServerApplicationContext: NoMyBatismapperwasfoundin'[xxx.xxx.xxxx]'package.Pleasecheckyourconfiguration.WARN22052---[      main]ConfigServletWebServerApplicationConte......
  • JAVA:mapper.java和mapper.xml的关系,以及foreach的用法
    简单理解就是,java声明了方法,xml实现了方法,类似与接口与实现接口,他们之间的关系如下:// Mapper.java中List<Ranks>inquireOnlyName(@Param("names")List<String>names,@Param("status")Stringstatus,@Param("startIndex&qu......
  • Mybatis使用generator逆向工程生成器生成entity、mapper、.xml模版类
    前言今天将表建好了,但是一个一个的建实体类、Mapper接口、Mapper.xml文件就十分的麻烦,所以我就想到了MyBatis逆向,今天就操作一把!这里我们采用maven来进行操作。一、新建generatorConfig.xml文件首先建好表,在你的项目的resource文件中新建generatorConfig.xml文件。代码如下:<?xmlv......
  • Spring Boot学习随笔- 集成JSP模板(配置视图解析器)、整合Mybatis(@MapperScan注解的使用
    学习视频:【编程不良人】2021年SpringBoot最新最全教程第五章、JSP模板集成5.1引入JSP依赖<!--引入jsp解析依赖--><!--C标签库--><dependency><groupId>jstl</groupId><artifactId>jstl</artifactId><version>1.2</version></depen......
  • 使用AutoMapper
    1、在控制台中namespaceStudyAutoMapper{publicclassFoo{publicintID{get;set;}publicstringName{get;set;}}publicclassFooDto{publicintID{get;set;}publicstringName{get;se......
  • mapper 向后端传集合出错
    批量查询<selectid="selectGoods"parameterType="cn.com.xxx.xx.entity.Goods"resultMap="goodsResultMap">selectg.GOODS_ID,g.GOODS_NAME,g.GOODS_CODE,g.GOODS_DATE,g.GOODS_STATE,g.GOODS_NUM_STOCK,g.GOODS_PRICE,g.GO......
  • mapper中limit参数的问题
    通常情况下一般不会用limit进行分页操作,但是在数据量小的情况下使用limit还是挺好的,因为方便。在mapper中操作一般我们都是这样写,看起来没问题,但是跑起来会有问题。因为limit中不支持动态运算符,故在写分页的时候mapper.xml中以下这种写法是错误的://错误写法<selectid="queryPag......