本文继续讲述 NES 的基本原理,承接上文的 CPU,本文来讲述 PPU,较为复杂,慢慢来看。例子基本都是使用的魂斗罗,看完本文相信对那问题“为什么魂斗罗只有128KB却可以实现那么长的剧情”有一定答案。
看本文之前最好看一看前面两篇文章,本篇会有前文涉及到的部分,[NES基本原理(一)总述] ,废话不多说,来看今天的内容:
PPU 有自己的总线,再来看看这张图:
可以看出通过 PPU 总线能够访问到的地址空间主要由三部分组成:PatternTable, NameTable, Pallete,其中 PatterTable 是映射到卡带里的 CHR
这里说明一下,关于上图前两篇文章有错,PatterTable 是在 NameTable 前面的,这里更正一下,公众号似乎不支持修改图片,我在前文标注一下吧。
有着大致概念之后,来看具体的空间布局,关于这,任天堂给出的图还是很清晰的:
看了前文,应该会对这些名词比较熟悉,前文也简要介绍了这些 Tables,下面就来详细的看看:
PatternTable,映射到卡带的 CHR,CHR 可能是 ROM,也可能是个 RAM。
PatternTable,中文名叫图案表,故名思意,里面存放的是游戏使用到的图案,一个图案称为一个 tile。NES 游戏不论背景还是角色等精灵都是由一个个的 tile 组成。一个 tile 像素,NES 游戏屏幕大小为 像素,所以由 个 tile 组成(这里相当于算的是背景由这么多个 tile 组成,精灵的话要另算)。
由上图可以看出,有两个图案表,一个图案表 4KB,图案表总共占 8KB。但其实一个 NES 游戏的图案表可能不止两个,总大小可能会超过 8KB,但 PPU 对于 PatternTable 这部分能寻址到的就只有 8KB,所以在某一时段,PPU 最多也就支持 2 个 PatternTable,那我想用其他的 PatternTable 怎么办?这就是前文简要提到过的 Mapper 来干这事了,游戏代码逻辑控制 Mapper 映射当前的地址空间映射到 CHR 里的哪一个 PatterTable
这里我们不讨论那么多,就当 2 个 PatternTable 来讲解说明。PatternTable 里面存放的到底是什么?存放的就是一个个图案 tile,看个例子,emmm 前面举了太多的超级马里奥的例子,这里来看个魂斗罗的例子:
这里不要关注颜色,颜色是我专门这么设置的,感官上要容易辨认一些。这些图案看着还挺清楚像那么一回事是吧(这是 模式下的样子,这模式后面讲述精灵的时候详述,主要是这种模式下 PatternTable 好辨认些)。
网传魂斗罗这游戏有 128KB,我这上面 .nes 格式的文件有 129KB,也都差不多,相对于一般的 NES 有些来说算是大游戏了,它的 PatterTable 就有多个,这里我只是截取的游戏开始那一段使用的图案表。
由上可以看出一个 PatternTable 是一个个图案也就是 tile 组成,一共由 256 个 tile 组成,这里我们可以简单计算一下:
一个 PatternTable 4KB,那么一个 tile 就是
一个 tile 像素,一个像素使用
这 2bit 信息是什么?这 2bit 就是颜色信息的一部分,它们来构成了图案。在 的像素中,通过“点亮”某些像素,“熄灭”某些像素,就可以形成图案,而这里所谓的“点亮”和“熄灭”就是通过赋予该像素 (00, 01, 10, 11) 来实现的,举个例子,GAME OVER 的 O 这个 tile:
这个图也是根据 FCEUX 这个模拟器截出来的,是没有上色的灰阶图像,可以看出,"O" 这个 tile 在 PatterTable 中的索引为 ,地址为:0030。
换个更本质一点的数字版本:
这就是 tile 的本质,“64 个 2bit” 信息,仔细看的话,这 2bit 其实是当前这个 tile 使用的 Pallete 中 4 种颜色的索引(对照上图和上上图来看,后面 Pallete 部分还会详述)。
之所以将 “64 个 2bit” 打上引号,是因为实际存储时,将这 2bit 的高位和低位分开存储,先存储 64 个像素的低位,再存储 64 个像素的高位。
PatternTable 就先说到这,下面来看 NameTable。
NameTable 是背景使用的,背景占据整个屏幕,也就是说背景由 个像素 个 tile 组成,这 个 tile 得有一定的次序排列,才能组成正确的背景画面,而 NameTable 就是记录这个次序的。比如说第一个 tile 槽使用哪个 tile,第二个 tile 槽使用哪个 tile,NameTable 就记录这个信息,记录 个 tile 槽的索引。
这里又来简单的计算一下:一个 PatternTable 里面有 256 个 tile,索引 256 个 tile 需要 ,一屏有 个 tile,所以 一个 NameTable 就需要 960B,这与 PPU 的地址空间布局图是一致的。
由那张 PPU 的地址空间布局图可以看出,PPU 支持 4 个 NameTable 的,但是实际物理上只支持 2 个 NameTable。这部分空间是位于 PPU 内部的,是 PPU 的内存,对比现在的显卡,这部分空间就是显存 VRAM,一共 2KB,它的大小只够支持 2 个物理 NameTable。但是有的卡带和其 Mapper 支持超过 2 个 NameTable,道理同上 PatternTable,多出来的这部分空间位于 卡带,由 Mapper 控制映射。这里我们不讨论那么复杂的情况,这里就讨论 PPU 原生支持的 2 个物理 NameTable / 4 个逻辑 NameTable。
这 4 个 NameTable 的逻辑布局如下图所示:
第一个 NameTable 位于左上角,第二个 NameTable 位于右上角,第三个 NameTable 位于左下角,第四个 NameTable 位于右下角。
每个 NameTable 就能存放一屏的 tile 索引,但实际上游戏预先存放了 2 屏的数据,另外两个 NameTable 就是镜像,镜像分为多种方式。从逻辑上说,我们平时玩游戏时看到的屏幕画面都位于上图的范围内。
Horizontal Mirroring,水平镜像,示意图如下:
这种镜像是 1、2 NameTable 一样,3、4 NameTable 一样,左右一样,所以叫做水平镜像。使用这种镜像的一般是上下移动的游戏,常见就是 雷电、兵锋这类游戏,比如说 兵锋 刚开始时的 4 个 NameTable 如下所示:
Vertical Mirroring,垂直镜像,图示如下:
道理同上,我就不具体解释了,一般左右移动的游戏使用这种镜像,比如我们熟悉的超级马里奥:
Single 镜像,4 个 NameTable 是一样的东西,我没有仔细的去找使用这类镜像的游戏,而且 FCUEX 这个模拟器似乎不支持 Single 镜像。按我想的,使用这类镜像的游戏应该像是 大金刚 这类只有固定一屏的游戏,我看了下 大金刚 的 NameTable,的确只有 1 个 NameTable 有效,但却是水平镜像,另外的 NameTable 填充的无效数据并没有使用,如下所示:
四屏镜像(感觉都不叫镜像了),示意图如下
从名字从示意图来看就知道,这 4 个 NameTable 都不相同,前面曾说,物理上 PPU 的 VRAM 只支持 2 个 NameTable,也就是说最多只有 2 个 NameTable 不同,那这里有 4 个 NameTable 都不同,那么需要额外的空间,这部分空间位于 卡带,同样的如前所述,只有部分游戏和卡带以及相应的 Mapper 才支持 Four-Screen 镜像。
使用这类镜像的游戏我没玩过,也就不拿具体的例子来说明了,资料显示有 公路之星2,圣铠传说 等游戏(emmm,听都没怎么听过)
那魂斗罗呢?魂斗罗是主要是横板游戏,使用的是垂直镜像,就算像是第三关上下移动,但也还是垂直镜像,只是同 大金刚 一样,只有一个 NameTable 有效:
这是魂斗罗第三关使用的 NameTable,垂直镜像,所以上下是相同的,但是右侧的两个 NameTable 并未使用,所以实际上只有 1 个 NameTable 有效。
NameTable 就先说到这,记住它是一屏背景 960 个 tile 的索引就行了,下面来看 AttributeTable。
PPU 地址空间能够寻址到的内存有 2KB,支持 2 个 NameTable,花去 ,还剩下 ,简单来说 一个 960B 的 NameTable 搭配一个 64B 的 AtrributeTable。如果说 NameTable 是记录 960 个 tile 的位置关系,那么相应的 AtrributeTable 就记录这 960 个 tile 的一部分颜色信息,注意是一部分颜色信息(还有一部分是前面的 PatterTable)。
64B 要记录 个像素 个 tile 的颜色信息,虽然只有部分颜色信息,但听起来仍是有些不可思议,来看 NES 是如何做的:
每 的 tile 使用 1B,将这 再分成 4 份,每 tile 分得 2bit。
所以 2bit 就控制着 个 tile, 大小的像素区域,挺抠门的是吧,节约到极致,至于这 2bit 信息表示什么以及 PatternTable 那 2bit 表示什么后面 Pallete 再说。这里记住 64B 的 AtrributeTable 管理着整个 NameTable 的一部分颜色信息,其 2bit 就控制着 个 tile 的颜色信息。
NameTable 和 AtrributeTable 这两者是一一对应的,一个 NameTable 加上 一个 AtrributeTable 占据 1KB 的内存,PPU 的 VRAM 有 2KB,所以物理上支持 2 个这样的组合。
PPU 关于这部分的地址空间是从 3FFF,总共 8KB,4 个逻辑上的 NameTable 和 AtrributeTable 加起来也才 4KB,后面的 4KB 是前面的镜像。
关于 NameTable 和 AttributeTable 就先说这么多,下面来看 Pallete 部分。
Pallete 调色板,不同的 PPU 芯片使用的调色板可能不同,大体上说都是这个样子:
理论上可以总共可以使用 64 种颜色,但是从上图可以看出明显有些颜色是一样的,所以少于 64 种。这里再次说明,不同的 PPU 支持不同,这里说的一般情况。
怎么表示这些颜色呢?这就分颜色系统了,我们最熟悉的就是 RGB 颜色系统,R G B 分别表示红绿蓝三个颜色通道,每个分量的取值为 [0, 255],比如说 00 号颜色的 RGB 表示为 (84, 84, 84)。
由 PPU 地址空间布局图可知,Pallete 区域为 3F20,其后的空间是这部分区域的镜像。
存放在这部分空间的并不是颜色本身,比如说用 RGB 来表示颜色,这部分区域并不是存放 (R, G, B) 三元组,而是存放的是颜色索引 ,01 等等。
关于颜色部分抠门的地方来了,上面那个调色板可以看作是总的调色板,但实际使用的是 8 个子调色板,每个子调色板包括总调色板中的 4 种颜色。便于叙述后面我就称这子调色板为 Pallete。
1 个 Pallete 包括 4 种颜色,其实是包括 4 种颜色索引,“64” 种颜色只需要 5bit 来索引,但这里索引用 来表示,还是很大方的没有像其他地方那么“抠门”。
8 个 Pallete,需要 ,刚好与 3F20 对应。
抠门的地方又来了:这 8 个 Pallete 前四个是给背景使用的,对应 3F10,后四个给精灵使用,对应 3F20。
抠门的地方又又来了,每个 Pallete 的第 0 个(我习惯上将索引从0开始的起始元素叫做第 0 个)颜色是相同的,对于背景来说,这个颜色是通用的背景色,对于精灵来说,这个颜色就是透明色不渲染。
所以对于背景来说,可以使用 种颜色,对于精灵来说 种颜色。
比如魂斗罗刚开始时使用的 8 个调色板:
这里多说一句,背景第个的号颜色存放通用背景色,3F04/3F0C 分别为背景第 1/2/3 个 Pallete 的 00 号颜色,它们可以存放不同的颜色,但是 PPU 渲染的时候通常不会使用它们,而是直接使用 中的通用背景色。3F10/3F18/3F00/3F08/$3F0C 的镜像。所以说其实一般情况下,这 8 个 Pallete 的 00 号颜色其实是一个色。
讲到这里,就可以来解决上述遗留的问题,对于某个 tile 来说,PatternTable 中记录的 2bit 和 AttributeTable 中记录的 2bit 分别表示什么。
AttributeTable 中记录的 2bit 表示某个 tile 使用哪个 Pallete,因为背景使用的 Pallete 只有 4 个,2bit 索引就足矣,PatternTable 中记录的 2bit 表示 tile 中的某像素使用这个 Pallete 中的哪个颜色,因为 Pallete 中有 “4” 种颜色,2bit 索引足矣。
这里还可以得到这样一个事实:AttributeTable 中 2bit 控制 个 tile 使用的 Pallete,所以一个 tile,或者说相邻的 4 个 tile 最多就只能使用 4 种颜色。
这是魂斗罗开始场景的截图,每个蓝色方格代表 个 tile,大致还是可以看出,每个蓝色方格里最多就使用了 4 种颜色。
前面讲述的 PatternTable, NameTable, AttributeTable, Pallete 都是 PPU 地址空间中可寻到的。PPU 还有一部分较大的内部的内存,并没有包含在 PPU 地址总线可寻到的地址空间里面。
这部分内存叫做 OAM,Object Attribute Memory,用作精灵的属性信息。这里的 Attribute 并非上述讲的 Attribute,这里的 Attribute 含义更加广泛。
OAM 总共 256B,支持 64 个精灵条目,也就是说每个精灵条目有 4B 的信息。这 4 字节,每个字节都有不同的含义:
第 0 个字节记录该精灵的 Y 坐标,以像素为单位,坐标示意图如下
tile 索引,表示该精灵使用的是哪个 tile
关于精灵使用的 tile 有两种模式,一种是 模式,一种是 模式,这由寄存器($2000) 控制。
顾名思义, 模式的精灵宽 8 高 8,1 个 tile 组成,而 模式的精灵宽 8 高 16 实际上由 2 个 tile 组成。
对于 的精灵来说,Byte1 存储的 tile 索引就是该 tile 的索引。对于 的精灵来说,Byte1 存储的 tile 索引为该精灵上侧的 tile 索引,而下侧的 tile 索引为 。
来看个例子,来源于魂斗罗偶数关卡角色的一部分:
精灵的属性:
使用哪个 Pallete 道理同背景,这里的 2bit 是在精灵的 4 个 Pallete 中索引。
精灵优先级在后面渲染的时候再说明,这里也可简单说一下:当精灵与背景重叠时,那么应该是渲染精灵的像素还是背景的像素呢?当两者的颜色都不是(透明色/通用背景色,也就是说颜色索引不是00) 时,如果精灵有背景前的优先级,那么渲染精灵的像素,如果精灵使背景后的优先级,那么渲染背景的像素。
翻转也是前面所说的抠门之一,有些 tile 只要翻转一下就可以当作另一个 tile 使用。在魂斗罗第二关有种跳来跳去的敌人:
可以看出它的下半身是对称的,这两个精灵信息如下:
可以看出 PatternTable 中 实际上并没有 “左腿” tile,只有 “右腿” 的,将 “右腿” 翻转一下作为 “左腿” 使用,所以这两个精灵其实都是索引为 和C3 的 tile 组成的。
至于垂直翻转也是同样的道理,具体的例子一时没找出来,就不举例说明了。
该精灵的 X 坐标,以像素为单位,道理同 Byte 0 不再多说。
由前文可知,视频都是一帧一帧的画面组成,帧与帧之间的空隙叫做 V_Blank,这段时间一开始 PPU 就触发 NMI 中断,然后 CPU 执行 NMI 中断服务程序。通常就是这个时间段将更新好的精灵信息搬运到 PPU 的 OAM 当中。CPU 的 RAM 2FF 这 256 字节通常存放的是精灵信息,CPU 运行游戏代码对这 256 字节的精灵信息更新,然后在 V_Blank 期间将其搬运到 PPU 的 OAM 中。所以说每一帧画面最多支持 64 个精灵。
另外这里讲述的 OAM 全名叫做 Primary OAM Memory,还有 Secondary OAM Memory,实际上就是 Primary OAM Memory 的一个缓存,其大小支持 8 个精灵信息。前面我们说过,一帧画面有 240 条可见的 Scanline,这 Secondary OAM Memory 就是用来存放当前 Scanline 将要渲染的精灵信息。所以说一条 Scanline 上最多只有 8 个精灵。
本文就先说到这吧,也算是对魂斗罗有了个简单分析,根据上述的一些计算大概知道为什么一个游戏那么小,“抠门”优化节约到了极致。这篇只是讲述了 PPU 关于内存的一部分,对于它的寄存器,如何滚屏,渲染等等还未讲述,涉及到 PPU 一些硬件,留待后面讲述。
了解到这其实可以进行简单地 NES 程序开发了,只不过关于 PPU 的内存如何访问,CPU 和 PPU 如何交互信息,比如如何搬运 OAM 数据等等都未讲述,关于这部分如何使用 6502 汇编进行相应操作,emmm 我后面闲得话再讲述吧。
好了本文就到这里,有什么还请批评指正,也欢迎大家来同我讨论交流。
本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/lJPAY3c2N5AgbMzA7p7-Uw
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。