相关影像
型号
主板
图示
快速入门
GameBoy(GB)系列可以看作 NES (即日版的 FamiCom) 的便携版,只是在性能上受到了限制。不过,它的一些非常有趣的功能,仍然能够让我们眼前一亮。
型号多样化,分析也要多样化
该掌机的火爆导致其各种变体的出现(例如 Pocket、Light,甚至是兼容 超级任天堂 的型号)。 其实,GameBoy 系列掌机横跨两个世代(即第四、第五世代): 第四世代诞生的是单色版的 GameBoy(以及它的各种改进版本);而在第五世代诞生的是 GameBoy Color(虽然有时也被归为第四世代,但它比第五世代的 Virtual Boy 出现得更晚)。 好消息是,这篇文章将这两款都包括在内。 所以读完这篇文章,您会很好地理解 GameBoy 的工作原理,以及它是如何演变成 Color 版本的。
中央处理器 (CPU)
任天堂没有选择在主板上放置许多现成的芯片,而是采用 单芯片设计 来容纳(和隐藏)包括 CPU 在内的大部分组件。 这种芯片被叫做 SoC(System on a Chip,“片上系统”)—— 在这里,SoC 就是专门为这款游戏机打造的芯片,这使得任天堂能够根据自己的需求(能效、反盗版与额外的 I/O ,等等)进行定制。 同时也意味着,这种芯片不可能通过零售渠道买到,这让当时的竞争对手更难以仿制它。
GameBoy上使用的 SoC 被称为 DMG-CPU(也叫 Sharp LR35902)[1],从名字里可以看出,这是由 Sharp 生产的。 这家公司和生产 NES CPU 的供应商 Ricoh 一样,与 Nintendo 的关系非常密切。
CPU 核心
DMG 的主处理器是 Sharp SM83 ——这是 Zilog Z80 与 Intel 8080 相融合的产物。Z80 在当时的应用非常广泛,你可以在家用计算机、德仪图形计算器,以及 Sega Master System(SMS) 和 Game Gear 中见到它。 SM83 运行于大约 4.19 MHz,看上去比 1 MHz 的CPU更快;但这里必须指出,处理器的时钟频率有时是会 骗人 的。
回顾我们在 SMS 上的分析,我说过“Z80 是 8080 的‘超集’” 。 所以与这两个处理器相比,SM83 多了什么,又缺了什么? [2]
- 它既没有 Z80 的
IX
和IY
寄存器,也没有 8080 的IN
、OUT
这两种指令, 这意味着它根本就没有 I/O 接口。 我并不清楚这是不是为了节约成本,但这一点意味着硬件设备需要 完全的内存映射,才能与 CPU 进行交互。 - 只具有类似 8080 的寄存器组。 因此,SM83 只有7个通用寄存器,这与 Z80 的 14 个寄存器不同(在 Z80 中,每个寄存器都有其“备份”)。
- 包含了 Z80 的部分扩展指令集,但只限于三种位操作指令。
此外,Sharp 还增加了一些不存在于 Z80 和 8080 的 新指令 , 这些额外的指令针对 Nintendo 与 Sharp 对硬件的安排进行优化。 其中一个是 LDH
,即“读取高位地址内存”(LoaD from High memory)[3] —— 这里的“高位地址”,位于内存的最后 256 个字节,即开始于 $ff00
。这样写程序的时候可以少写一个字节,速度也更快一些。
彩色效果
过了将近 10 年,随着 Virtual Boy 与它的 先进技术 被人遗忘,一个不起眼的继任者出现了:GameBoy Color(GBC,代号 CGB), 里面的新 SoC 被叫做 CPU CGB。它的功能更多了, 但它的核心 SM83 还在,只是时钟频率翻倍,达到约 8.38 MHz。
很难想象十年后 Nintendo 仍然捆绑使用同一颗 CPU。但这种方案仍然有一些好处:
- 开发者可以在新主机上沿用曾经的编程技能。
- 不需要为一个新架构重新设计他们的游戏系统,这可以省一些钱。
- 向后兼容不费吹灰之力。 其实,这颗核心可以通过编程改变工作模式:
- 正常模式,SM83 在通常时钟频率下运行(约 4.19 MHz),以适应原版 GameBoy;
- 二倍速模式,SM83 的时钟频率翻倍,达到约 8.38 MHz。这是 GameBoy Color “原始”的时钟频率。
但在九十年代后期,仍然使用这种过时技术是要被玩家痛骂的。 稍微看一眼 当时 CPU 的市场行情,就能明白这个掌机究竟错过了什么(但说实在的,Nintendo 保守不保守真的很难讲,例如 Virtual Boy)。
硬件访问
SM83 沿用了 8 位数据总线** 和** 16 位地址总线,可以寻址 64 KB 的内存。 内存映射的结构如下[5]:
- 存储卡带若干区块的空间(Block 0 和 Block else);
- 工作 RAM(WRAM)、高位地址 RAM(HRAM)和显示 RAM(VRAM);
- I/O(按键、音频、图形与 LCD);
- 中断控制。
这些都将在后面为大家说明。
可用内存
Nintendo 装在主板上的 8 KB RAM 是为“一般用途”准备的,这部分就是所谓的 WRAM。 这一大小可是 NES 的四倍。
另外还有 127 B RAM 位于 SoC 中, 这便是 HRAM。借助 SM83 独特的 LDH
指令,这部分空间的数据能够以更快的速度读取。 这与 6502(NES 上的处理器)上的“Zero Page”模式非常相似,它也是利用内存位置优化性能的。 从技术上讲,它跟外面的那部分相比没有实质性区别,但这是 CPU 优先访问的区域。 这里先放一边,等到“图形”章节讨论到 DMA (Direct Memory Access,直接内存访问)组件的时候,您就会明白这意味着什么。
在 GameBoy Color 中,WRAM 扩大到 32 KB。 然而,由于 CPU 还是那个 CPU(特别是因为它有限的内存总线),直接把这些内存加进去会造成地址空间溢出,显然很不现实。 为了解决这个问题,Nintendo 的工程师引入了 “地址组切换” 机制。 这种机制继承自 NES 的卡带,使得 GameBoy Color 可以只使用 8 KB 的内存来访问 32 KB 的 WRAM。 技巧相当简单:8 KB 内存中,后面的 4 KB 可以在 7 个不同的 Bank 之间进行交换。 这样一来,为了让开发者能够检查扩展内存,CPU 又捆绑了一个额外的寄存器,即 SVBK
,作为地址组切换器。
图形
所有的图形计算都由 CPU 完成,然后由 图形处理单元(PPU)进行渲染。 PPU 是 DMG-CPU 内部的另一个组件,可以说是 前代图形芯片(同名)的改进版。
图像显示在集成的 LED 屏幕上:它具有 160 x 144 的分辨率;在单色版本的 GameBoy 上,每个像素可呈现四种灰度(白、浅灰、深灰、黑)。 不过,因为原版 GameBoy 的 LED 屏幕呈绿色,实际看上去是 发绿 的。
如果您读过NES的文章,您或许会记得 PPU 是为 CRT 电子束设计的。 但很显然,GameBoy使用的是液晶屏幕。 不过,这颗新的 PPU 采用了同一种技术,因为液晶屏幕也是逐行刷新的。 如此一来,主机也有了 如同CRT一般的特效,让开发者能够尽情发挥自己的想象力。
硬件组织
PPU 与一个 8 KB 的 VRAM 相连。 这样一来,PPU 就需要通过仲裁机制,从 CPU 手中拿过对内存的控制权。 这 8 KB 包含了PPU渲染图形所需的大部分数据。 其他的数据就直接储存在 PPU 中,因为它们需要更快的读取速率。
游戏负责在不同区域填充正确类型的数据。 此外,PPU公开了寄存器,因此游戏可以指示PPU如何组织数据。 尽管如此,仍有许多规则需要遵循(您将在以下章节中看到这些规则)。
构造帧
来看看 PPU 是如何在屏幕上渲染图像的。 为了演示,我用 Super Mario Land 2(超级马力欧大陆2 六个金币)作为例子。
图块
PPU 使用 图块(Tiles)作为渲染图形的基本元素 —— 更具体地说,是 精灵和背景。
所谓“图块”就是一张 8x8 的位图,它存放于 VRAM 里一个叫 图块集(Tile set),或者叫“图块模式表”(Tile pattern table)的区域中,每个像素对应四种灰度的任意一种。 这里的“灰度”是通过“调色板”(colour palette)来选择的。 单色版本的 GameBoy 有一个定义这种调色板的寄存器, 正如我之前所说,它只能选择四种颜色(或者说“灰度”),所以使用 8 位的寄存器来储存这种调色板是完全没有问题的。 尽管如此,系统还是提供了 3 个寄存器(也就是 3 个可编程调色板),但它们的使用受到 限制(稍后再详细说明)。
此外,图块还被归类到两个图案表中。
为了构建图片,图块被引用到另一种称为图块映射的表中。 这些信息将告诉PPU在何处渲染图块。 存储的两个映射用于构建每一帧的不同层。
下一章节会解释如何用图块构建图层。
背景层
背景图层是包含 静态图块 的图,大小为 256x256 像素(32x32 图块)。 但是,请您注意,屏幕上只能看到 160x144 的范围。也就是说,游戏要决定背景的哪些部分需要显示。 于是,游戏可以在玩家游玩的过程中,移动要显示的背景区域。这就是 滚动效果 实现的原理。
两个图块映射中的一个可用于创建背景图层。 另外,背景图层只能使用 一个 调色板。
窗口
“视窗”(windows)是一个 160x144 像素 的图层,包括显示在背景或精灵顶部的图块。 这个图层 不会 滚动。
剩下的图块可以分配给该图层;它们也可以与背景图层共用相同的调色板。
这个功能听上去很傻: 因为窗口图层没有透明度,它完全遮盖住了背景。您可能会想,“都遮住了还看个毛啊?” 嗯…… 其实视窗图层可以与背景 合用,分别显示屏幕的各部分。 该图层主要是为了在屏幕底部显示固定信息,只不过在 NES 上需要执行 复杂的定时写入,但 GameBoy 的 PPU 可以自动处理。
因此,游戏通常用它显示玩家的统计数据、得分等“常驻”信息。
精灵
“精灵”(sprite)是可以在屏幕上独立移动的图块。 它们可以互相重叠,也可以隐藏在背景后面,能否看到则取决于它们显示的优先级顺序。
这个图层还有额外的可用(或必需)的颜色:透明度。 这首先意味着它们只能显示三种不同的灰度,而不是四种。 幸运的是,这个图层特意预留了 两个 专用调色板可供选择。
对象属性内存(Object Attribute Memory,OAM)是 PPU 中专门存储精灵图块的内存区域。 不同于其他图块的是,精灵是由 OAM 定义的。 游戏一般通过调用 OAM DMA 单元 来填充这个区域,DMA 会从 RAM(或游戏 ROM)提取数据,并发送到 OAM。 不过,当 DMA 正在运行的时候,CPU 就不能访问 WRAM 了(这也体现了为什么 HRAM 这么重要)。
除了图块索引以外,每个条目还包括下列属性:X-Y 位置、所选的调色板、显示优先级与翻转标志(以允许垂直或水平翻转)。
PPU 的渲染存在限制,每行扫描只能渲染至多 10 个 精灵(即每秒 40 帧);超过这部分的精灵将不会被渲染。
结果
完成了一帧,是时候继续下一帧了! 然而,在 PPU 读取 VRAM 的时候,CPU 不能修改它。这样一来,当 PPU 闲置的时候,系统就要触发中断。 这种行为与 NES 如出一辙。
完成一行扫描后,水平消隐 周期开始(即从一行扫描线的末尾到下一行扫描线的开头,约 204 微秒), 给这一帧没渲染完的部分提供时间。
完成全部扫描后,垂直消隐 周期开始(即从最后一行扫描线的末尾到第一行扫描线的开头,约 1.1 毫秒),指定的某个中断被调用。 现在游戏可以更新下一帧的图像。
在扫描线开头,会触发一个名为 OAM search 的额外状态,此时 PPU 正在处理该扫描线中将显示哪些精灵。这时游戏可以更新除 OAM 以外的任何区域。
机密与限制
窗口层和额外中断的加入使新的内容和效果得以实现。
晃动效果
水平中断允许在帧渲染完成之前改变帧。 这意味着可以在每一行应用不同的滚动值,从而使帧的每一行以不同的速度移动。
这就实现了一种有趣的摇摆效果(Wobbling)(我不确定这是不是它的正式名称)。
添加色彩
Game Boy Color的PPU是原版的超集。 现在,您将看到该品牌所谓的“Color”机型增加了哪些功能。
操作模式
这是一款“GBC 增强”游戏,现在运行于 CGB 模式。
首先,出于兼容性的考虑,新的PPU有两种工作模式。 然而,任天堂希望Color用户即使只玩单色游戏,也能看到增强的效果。 因此,两种操作模式如下:
- CGB模式: 扩展PPU模式,包含新Game Boy Color游戏的所有视觉改进。
- DMG模式: 禁用所有额外功能的传统模式。 不过,你会在“操作系统”章节看到,单色游戏还是通过彩色调色板得到了增强。
整理(新)内容
CGB主板现在可容纳16 KB 的 VRAM,是原来 VRAM 容量的两倍。 由于CPU的寻址限制,这种新的安排以两个8 KB地址库的形式实现,由一个新寄存器(称为VBK
)作为切换器。 另一方面,PPU可以同时访问这两个存储体。 说到底,这意味着程序员只需借助VBK
填充VRAM地址库,然后在图块映射中指定图块所在的库,剩下的就交给PPU处理。
所以说,这些额外的 VRAM 可以做哪些事情? 很多很多:
- 存储两倍数量的贴图。
- 存储更多的调色板,色域更广了。
- 扩展贴图元数据空间来编码编码更多特效,以及处理额外的调色板。
视觉效果
得益于新的 PPU,现在程序员可以定义调色板了。他们有多达 32,768 种 颜色能够选择。
首先,开发者现在必须填充新的内存区域:调色板内存,它最多可以存储 16 个 调色板(一半给背景和窗口,一半给精灵),每个调色板编码 4 种 颜色 [6], 每种颜色由 16 位 / 2 字节的值来表示(但只使用其中的 15 位)。 此时 CPU 不处理调色板内存,但提供新的寄存器作为调色板内存的缓冲区(可以在 超级任天堂(SNES)上找到)。 总之,CPU 就是这么定义调色板的。
不过,“背景”和“窗口”图块可以引用这八个调色板中的任何一个。 同样的情况也会发生在精灵图块上,只不过它们只能使用三种颜色的调色板,因为有一个条目是为“透明”颜色预留的。
额外的空间
现在,图块集的大小是原来的两倍。 因此,程序员可以在VRAM中存储双倍数量的图块。 背景/窗口图块映射也得到了扩展,从而产生了额外的元数据编码。 从而扩展了这些图层的功能。 例如,它们的图块现在可以水平和垂直翻转,从而使游戏无需在VRAM中存储重复的图形(反过来,也可以利用这些图形绘制更多独特的内容)。
此外,CPU CGB还捆绑了一个额外的DMA单元,可将Game Pak或WRAM中的内容复制到VRAM中。 它以两种模式运行[7]:
- 通用DMA:随时进行传输,DMA优先于其他内存访问。 因此,程序员需要注意使用该组件的时间(即扫描期间或扫描之外)和方式(复制的数据量),因为错误使用会导致屏幕撕裂(传输期间VRAM访问受阻)。
- 水平消隐(H-Blank)DMA:传输只在H-Blank期间进行。 这可以避免屏幕伪影,但只能以16字节为一批传输内容,并在LCD扫描期间暂停。
该设备再次为程序员提供了提供更丰富内容的新可能性,因为它可以利用原本空闲的时间。
音频
音频系统由 音频处理单元(APU)执行,这是一颗具有四波段的 PSG 芯片 [8]。
奇怪的是,在不同型号之间,音频系统是少数没有改进的部分之一 —— 事实上,它甚至无法加速:如果改变振荡器的速度,你听到的不是 “更好”的声音,而是更高的音调。
功能
四个通道中的每一个通道都为特定的波形预留:
脉冲
脉冲波形有非常明显的哔声,所以它主要被用于旋律或音效。
APU预留了两个通道,每个通道可容纳一个脉冲波。 它们使用四种不同音调中的一种,通过改变脉冲宽度来构建。 第一个通道有一个专用的扫频控制。
由于通道数量有限,当游戏过程中需要播放音效时,旋律往往会被打断。 这一点在口袋妖怪红/蓝(Pokemon Red/Blue)等游戏中非常明显,因为在战斗过程中,小精灵的叫声会与所有音乐通道重叠;这也是为什么口袋妖怪的战斗音乐都不使用打击乐的原因。
波
APU允许定义自定义波形,以便从其第三通道听到。 波形由32个4位采样组成,存储在一个波表中。
该通道还可以控制波形的频率(使其能从同一入口产生不同的音符)和音量。
噪声
噪音基本上是一组听起来像白噪声的随机波形。 噪音波形被分配了一个通道。
游戏用它来创造 “鼓点”效果。
该通道只有两种音调可用,一种产生干净的白噪声,另一种产生机器人白噪声。 不过频率是可以调整的。
秘技与局限
混音器以立体声输出,所以不同通道可以分配到左声道或右声道。但只在插入耳机的时候起作用! 因为扬声器是单声道的。
另外,混音芯片与卡带的其中一个专用引脚相连,这能够在卡带的控制下,通过 额外的通道 输出模拟音频(但需要额外的硬件支持)。 不过直到最后,市面上也没出现使用这个功能的游戏;在 GameBoy Advance 的 向后兼容组件 中,也已经见不到这个引脚了。
操作系统
与直接进入游戏的 NES 不同,GameBoy 被设计成始终从内部 256 B 的 ROM (Boot ROM)启动,然后才跳转到游戏。 以下是启动过程 [9]:
- 主机打开后,CPU 从地址 0x0000 开始读取内存。前 256 B 正是其 Boot ROM。
- RAM 与 APU 完成初始化。
- “Nintendo” logo 的数据从卡带 ROM 复制到 VRAM,然后 PPU 从屏幕的顶部开始绘制它。 如果没有卡带被插入,logo 中就会有“垃圾图块”出现。 卡带没插好的情况下也会如此。
- logo 向下移动后,播放标志性的 po-ling 声。
- 游戏中的任天堂 logo 是与主机 ROM 中存储的 logo 相匹配的。 之后,主机会对磁带盒的 ROM 头进行 快速校验,以确保磁带盒正确插入。 如果检查过程出现任何问题,主机就会卡死。
- Boot ROM 从内存映射中删除。
- CPU 开始执行游戏程序。
不过,显示在屏幕上的 Nintendo logo 仍然在 VRAM 当中。这样一来,游戏就可以应用一些动画和特效来引入自己的 logo。这一点相当有可玩性。
启动过程的变化
就 Game Boy Color 而言,我们又一次发现 ROM 的内容发生了巨大变化。 例如,现在 Boot ROM 的大小为 2 KB [10];启动过程也有了新的行为:
- 现在,引导程序将检查插入的是 GameBoy 兼容的游戏还是 GameBoy Color 兼容的游戏,然后设定相应的寄存器,以激活 DMG(GameBoy)或者 CGB(GameBoy Color)模式。 程序会在卡带的 ROM 中检查特定的游戏元数据,它的结构在不同类型的游戏里有些区别。
- 如果插入的是 GameBoy 版的游戏,程序也会将计算出的调色板填充到调色板 RAM 中。这些调色板基于一种简单而巧妙的算法,也依赖于游戏的元数据。 这就是为什么原先支持 GameBoy 的单色游戏,在 GameBoy Color 这里可以显示出彩色。
- 在这个阶段,用户可以按下特定的按键组合,以更改引导程序的首选项。
- Nintendo logo 的检查现在也使用了 HRAM;但其本身已经失去了实际作用。
游戏
游戏用汇编语言写成,大小最多为 32 KB,这是有限的地址总线造成的。 不过,使用 地址组切换器(即之前提到的 动态映射),游戏可以变得更大。 市面上容量最大的 GameBoy 卡带,具有 1 MB 的 ROM(在 GameBoy Color 上,则是 8 MB)。
卡带可以内置一个实时时钟、一个外置电池,以及用于保存数据的 SRAM,但所有这些都是可选的。
卡带的类型
由于 Game Boy Color 支持两种模式,任天堂列出了 三种不同类型 的 Game Boy 游戏:
- GameBoy 版: 这种游戏与原版 GameBoy 完全兼容。 它总是以 DMG 模式运行。
- GameBoy Color 增强: 能够同时兼容两种型号。 虽然完全兼容单色模式,但在GameBoy Color上运行时,因为运行在 CGB 模式,视觉效果将会得到提升。 然而,为了保证与 GameBoy 的兼容性,总体上其功能受到限制。
- GameBoy Color 独占: 只兼容 GameBoy Color, 但能够充分利用该主机的机能。
外部通信
游戏第一次能够利用 GameBoy Link 线缆(即“对打线”)进行通讯,它提供了多人游戏的功能。 线缆采用的是非常原始的 串行通信接口(Serial Communication Interface, SCI)。
原版 GameBoy 的数据传输速率为每秒 8 千比特(即每秒 1 KB),在 Color 型号上可以达到每秒 512 千比特(每秒 64 KB);其中后者称“高速模式”。
另外,Color 型号还内置 红外发射与接收器,分别由红外 LED 和光电晶体管组成[12]。 这种装置可以实现无线通讯,就像在 宝可梦 金/银 等游戏里看到的那样。 然而,您会发现这个通讯系统不依赖任何协议:它只是有一个寄存器(名为 RP
)来编码它的动作(发射或接收)、传输的某一个比特和接收的最后一个比特(0
或 1
)。 即便如此,Nintendo 还是在官方的开发手册里编写了参考实现方案,以减轻开发者的困惑。
反盗版
正如您在 “操作系统”部分所看到的,控制台不会立即运行游戏,它首先会执行一系列检查,防止运行未经授权的卡带,并确保卡带 正确插入。
要通过这些检查,就必须把 Nintendo logo 的图块副本写入游戏 ROM 头部 [13],这样 Nintendo 就能以侵犯 版权与商标权 为由,对“未经授权”的开发商提出诉讼。 (真有你的, Nintendo)
不过,竞争对手 SEGA 后来也利用了这种技俩(Trademark Security System,TMSS):在开机时检查到字符串“SEGA”后才会启动。但后来的 世嘉诉 Accolade 案 认定任何公司都有权使用受版权保护的商标,因为这也属于合理使用。(在 Mega Drive 上市后,因为 SEGA 的封闭管理,为这个主机开发游戏非常不容易。因此 Accolade 对 Mega Drive 进行了逆向工程,以确保其兼容性;后来就被 SEGA 起诉,理由就是未经 SEGA 同意,“擅自使用” SEGA 商标,侵犯其商标权和版权。话说回来,SEGA 怎么好事轮不到,坏事都是它)
也就是说,游戏里面的反盗版措施要更加多样了。比如检查 SRAM 的大小(通常“未经授权”的卡带 SRAM 会更大),或者在游戏里随机对 ROM 进行校验。