-
下一个演讲 我个人十分期待
-
我也知道你们很多人为此在这里等候
-
我也非常激动
-
我自己有台GameBoy 我也很荣幸能拥有一台
-
我一直放着 有时也拿出来玩玩
-
当然一般情况下还是玩模拟器多
-
而且我只在模拟器上玩我拥有实体卡带的游戏
-
本来就应该是这样的 对吧
-
嗯是的
-
非常期待
-
顺便 我个人在Gameboy平台上最喜欢的游戏
-
第一个 是Megaman 2
-
随后是Wario Land, Mystic Quest 如果你不同意的话
-
那说明你还不够了解我
-
好了讲讲演讲吧
-
非常期待
-
主讲是Michael Steil
-
他在25C3给过一个非常棒的演讲
-
“The Ultimate Commodore 64 Talk” 现在
-
为大家带来的是 “The Ultimate Gameboy Talk”
-
很期待
-
Michael Steil 白天他在工作研究操作系统相关技术
-
晚上回到家就研究这些古董系统
-
在之前 它是个游戏机破解工作者
-
请为他热烈的鼓掌
-
把讲台交给Michel
-
大家好
-
那 我的名字是Michael Steil
-
这次讲座是“The Ultimate Gameboy Talk” (一场讲座,关于Gameboy的一切)
-
这场讲座的主要想法就是
-
在60分钟内 尽可能多得谈谈Gameboy的各种硬件细节
-
60分钟,关于Gameboy的一切
-
我准备了大约200张幻灯片 800张不同的表
-
所以信息密度可能比一般稍微高了一点
-
所以赶紧开始吧
-
这次的GameBoy演讲
-
算是一个大系列之一
-
我在几年前讲了Commodore 64
-
后来有人就接上讲了Atari 2600
-
讲了Galaksija 还有Amiga 500
-
所以现在又轮到我了
-
我选择了GameBoy
-
为什么GameBoy那么有趣
-
因为他们销售了很多很多的GameBoy
-
GameBoy和GBC加起来就有1亿1800万台
-
如果再考虑上兼容GameBoy的GBA机型 不包括GBM
-
加起来这几乎是2亿台机器
-
大约有1600款游戏
-
从1989年开始生产 8-Bit型号一直生产到2003年
-
一样,如果考虑兼容的GBA型号
-
8-Bit兼容机一直生产到2009年
-
也就是20年 相当厉害
-
我们再来看看当时的竞争对手
-
就在当时 就在GameBoy发布后
-
Atari发布了Lynx SEGA发布了Game Gear NEC发布了Turbo Express
-
这些竞品有一个共同点 它们都有彩屏
-
很棒的彩屏
-
但是还有一个共同点 就是渣续航 大约3-5小时
-
然而GameBoy可以做到15-30小时
-
然而妥协就是,只有一个这样的屏幕
-
而且一旦开始卷动就很难看清楚东西
-
当然,并不是所有的GameBoy都是这个情况
-
最初的GameBoy 也是生产最长时间的型号
-
最初代号是DMG 代表的是Dot-Matrix Game(点阵游戏)
-
1996年他们发布了GBP 带有效果好得多的屏幕 体积也小了很多 代号MGB
-
GBL只在日本发售 带有屏幕背光
-
最后是GBC 2倍的CPU速度 2倍的内存 2倍的显存 以及支持彩色
-
接着是GBA系列 架构完全不同 基于ARM CPU
-
但是仍然和GB、GBC游戏100%兼容
-
至于GBA SP,存在两种型号
-
如果你要买的话,记得买AGS101
-
也就是带有背光而不是前光的型号
-
而且可以看见任天堂总是有一点超前
-
不单单是做了翻盖设计 而且还需要一个转接头才能接一般的耳机
-
如果你想在电视上玩GameBoy
-
有两种选择 要么是Super Nintendo插上Super Game Boy
-
有两个版本 SGB2是日本专有型号 有专门的计时系统 不会比正常的快3%
-
以及Game Boy Player 搭配NGC使用
-
这三个都是内置了完整的GameBoy硬件
-
基本就是一个GameBoy 只是把图形输出到主机而不是自己的屏幕
-
所以GameBoy具体的外观
-
一个2.6英寸的屏幕 按键 单声道喇叭 耳机是立体的
-
有一个联机口 通过串行总线连接两台GameBoy
-
对比度和音量调节旋钮
-
背面 这里是插游戏卡带的地方
-
这里则是安装电池的地方
-
一般的游戏卡带就长这个样子
-
一般的游戏卡带里面一般也就是一片ROM芯片
-
没有什么特殊的 (具体后面会讲)
-
参数
-
GameBoy的参数是怎么样的
-
拿来和一些其它可能根本不具备可比性的机型比一比吧
-
CPU是1MHz的8Bit处理器
-
有人可能会讲这里错了 应该是个4MHz的CPU 但是我一会会解释为什么这里称之为1MHz
-
8KB的内存 对于这类的游戏机其实算是充裕了
-
显存(VRAM)也是8KB 稍微有点紧张
-
分辨率160*144 非常糟糕 但是对于这个屏幕尺寸 其实效果也还可以
-
同屏最大4种颜色 就是4级灰度
-
每行最多10个精灵
-
所以如果和这里其它的一些系统比较的话
-
很明显 GameBoy比Atari2600要先进得多 但是却又比不上SNES
-
更接近于一般的NES(美版红白机)或者是Commodore 64
-
有趣的是 NES和C64是在80年代早期发布的
-
GameBoy是89年
-
而且如我前面所说 兼容机一直生产到了2009年
-
这也就非常有趣了
-
它是8-Bit机 但是是最晚一批大量使用的8-Bit游戏机
-
看看内部
-
右边的板没什么花头
-
从正面看 LCD就是连接在这块板上 以及扬声器和按键
-
背后这块板就有趣多了
-
可以看见3块芯片 这个是DMG 也就是最初的型号
-
2片一样的RAM芯片
-
一片工作内存(WRAM) 一片视频内存(VRAM)
-
中间这个叫DMG-CPU
-
然而其实更应该被称为SoC(System on a Chip)
-
正常这类的系统都应该有很多芯片
-
但是这里全部都集成进了一个芯片 也就这个DMG芯片
-
来对比一下其它的GameBoy机型
-
比如SGB 这些芯片看起来很接近
-
其实基本上就是一样的
-
GBP 稍微优化了一下 只带有一片RAM芯片
-
GBL看起来基本没有区别 只是MGB系列的另外一个小型号
-
带有背光而已
-
接着是SGB2 基于GBP设计
-
这是GBC内部的样子
-
都有一个巨大的集成片
-
这个呢 这个比较特殊
-
可能从标识上不容易认
-
这个是GB Boy
-
总是有公司山寨GameBoy
-
这个型号 是一个相当完美的克隆
-
基本上就是 完全抄了一个原版的芯片
-
来自中国的山寨GameBoy
-
而且至今都可以在eBay上花三四十刀买到
-
然而很遗憾晶振快了30% 游戏都玩不了了
-
回来讲DMG的板子
-
DMG CPU还是相当有趣的
-
他接管整个系统的一切
-
DMG CPU包括了什么
-
CPU 中断控制器 定时器 内存 启动ROM
-
还有所有的外设以及IO控制器 摇杆 用于联机的串行控制器
-
声音控制器 还有 图形控制器
-
也就是PPU (Pixel Processing Unit)
-
来讲讲CPU吧
-
历史角度来讲
-
最初的GameBoy,1989年
-
发布时间是在NES的和SNES的之间
-
NES搭载的是6502处理器
-
SNES搭载的是65816处理器
-
也就是相同CPU的16位版本
-
所以显然GameBoy搭载了SHARP LR35902 (强行显然2333)
-
SHARP LR35902是什么
-
这个和6502没啥关系
-
更接近于i8080和Z80
-
但是也不是其中任何一种
-
两种cpu都相当有趣
-
比如8080用于Altair
-
也就是Bill Gates最初写程序并销售的平台
-
Z80则是用于所有没有采用6502的8bit家用机
-
相当成功的架构
-
所以如果你想象 这是i8080的功能
-
这是Z80的功能
-
也就是一个超集 而且完全向下兼容
-
然后这个 是GameBoy CPU
-
核心架构是相同的 也就8080的那些
-
比如寄存器组 指令编码 这些都是一样的
-
当然也有一些不支持的功能
-
但是又支持一部分Z80的功能
-
然而大部分的Z80功能都不支持
-
接着又在这之上加了一点自己的功能
-
来看一遍吧
-
先来讲讲8080的架构
-
它拥有这些寄存器
-
一个累加器 可以用于进行算数运算 其它寄存器不行
-
一个状态寄存器
-
在GB内 只有两个有用的标志位 零 和 进位
-
剩下两个是用于十进制调整的
-
然后是BCDEHL 6个8位寄存器
-
但是你可以把B和C合起来 变成BC
-
DE HL同理
-
所以你实际上拥有可以作为指针的16位寄存器
-
所以加起来一共有4个16位计算器
-
7个8位寄存器 加上一个特殊的指针寄存器
-
指向hl寄存器指向的内存地址的数据
-
可以放到任何可以操作寄存器的指令中使用
-
然后来看指令
-
读取/存储指令 同一个指令可以直接或者间接寻址
-
堆栈是16位的 只能操作16位寄存器
-
这些是算数和逻辑指令
-
如之前所说 这些指令只能配合累加器使用
-
inc和dec(自加自减)指令是例外 可以配合任何寄存器使用
-
而且也可以配合16位寄存器使用
-
移位指令 还有控制指令 跳转 调用 返回 条件 间接操作 等等
-
还有一些杂类的指令 清除设置进位标志 空指令 停机 停用启用中断
-
中断模型
-
大部分当时的机器都有一个中断向量来控制中断
-
然而这个上面 并不是向量 也不止一个
-
他并不是跳转到一个中断向量
-
而是跳转到内存中开始部分一个固定的地址
-
不同的中断对应不同的地址 比如0x40 0x48这种
-
还有一些软件中断
-
你可以使用特殊指令跳转到这些地方
-
RST 0是一个特殊指令 因为就相当于RESET
-
当你启动8080 CPU 他就从0地址开始执行
-
来谈谈一些不被支持的8080功能
-
这个是GB的标志位 这个是8080的标志位
-
它有两个额外的标志 一个是符号位 还算有点用 一个奇偶校验 就不太有用
-
所以这些指令都是不支持的
-
还有一些其它指令 因为种种原因 他们决定不包括这些指令
-
端口IO 你可能在8086上听说过 有独立的端口空间
-
在8080上也是支持的 但是GameBoy上不支持
-
因为GB使用了MMIO(内存映射IO)
-
Z80支持大量额外的移位和位移位 设置位 清楚位指令
-
这些都是支持的
-
相对跳转 也就是更优化的跳转指令
-
从中断返回
-
这些都是支持的
-
而不支持的则是一些Z80有趣的功能
-
比如备份寄存器组 额外的寄存器 还有很多很多功能
-
还有适合复制内存的自加循环指令
-
不过他们也有一些自己的指令来代替这些
-
比如它具有访问预减后加指令
-
比如你要访问hl指针 可以使用预减指令或者后加指令
-
还有一个叫做 第0页 (Zero Page) 的概念
-
这个叫法有点晕 因为并不是真正的第0页
-
而是在内存的顶部
-
如果你了解6502就知道 这个是从6502借来的概念
-
含义只是对于在内存最上端的数据可以优化编码
-
比如原先这样载入需要3个字节 执行需要4个时钟机器周期
-
现在可以写成这样 也就是2个字节 执行需要3个机器周期
-
显然得在最高的位置放一些有用的东西
-
特别是对计时敏感的东西
-
还有一些额外的堆栈指令
-
存储SP的指令 一个用于交换一个字节高低4位的指令
-
这样8个指令 以及一个额外的电源指令
-
操作码表看起来是这样的
-
表明了颜色所以看起来更加直观一点
-
有几个操作码是无效的 或者说没有被用到
-
如果执行的话都会造成死机 应该算是个好设计
-
这个比较特殊 操作码CB
-
是个操作码前缀 以此为前缀又有256个操作码
-
这也就是从Z80借来的滚动、移位指令 以及自己新增加的指令的空间
-
再来看另外一个指令 只是作为一个例子
-
这是从一个固定地址载入到累加器
-
表示需要3个字节 在4MHz下需要16个时钟
-
虽然存在争议 就是应该是1MHz还是4MHz (实际4MHz 但是把4个周期当1个看)
-
因为所有的时钟周期数都是可以被4整除的
-
因为整个系统都是和内存挂钩的
-
CPU只能以RAM能够提供数据的速度来计算
-
所以你可以说这是一个1MHz的CPU
-
然后这个指令需要4个周期
-
这个数字就小得多
-
而且这个数字也才可以和类似的系统进行比较
-
比如说和同样拥有1MHz内存速度的6502机器比较
-
所以说 理论上 CPU确实频率是4MHz
-
RAM速度是1MHz
-
PPU以4MHz的速度绘图
-
连接到速度为2MHz的VRAM
-
所以这里就稍微有点复杂
-
但是大部分情况下
-
大部分的数据可以以1MHz为基准表示
-
但是要精确的话 并不是1MHz
-
而是1MiHz 1024*1024Hz
-
所以他们没有使用十进制 而是用了二进制
-
很有趣
-
所以以后我提到周期 我说的是1MHz的机器周期
-
所以这是一个拥有16位地址空间的8-Bit CPU
-
因为拥有16Bit的指针 所以一共也就是64KB的可见地址
-
32KB的是ROM 直接来自卡带 映射到卡带
-
然后在上方有一个Boot ROM 一会提
-
VRAM也映射在这里 可选的外部RAM 以及内部RAM
-
没有使用的部分 要么没有东西 要么就是镜像已有的
-
把最高地址的这些放大
-
可以看到另外一页的OAM内存 就像是一种特殊用途的VRAM
-
独立于VRAM 一会会具体讲
-
最后一页 也就是第0页 包括了IO部分
-
所有的寄存器 声音的视频的
-
还有127字节的HRAM 独立于其它的RAM
-
所以这代表游戏只能有32KB
-
有些游戏确实只需要32KB
-
比如说俄罗斯方块 就刚好挤进32KB 里面就一片芯片
-
生产也很方便
-
然后其它的卡带
-
容量没有理论上限 但是实际上最大是到2MB
-
这个是128KB
-
实现的办法是 增加一个MBC (内存分页控制器)
-
一个特殊的可以切换分页的芯片
-
这个在各种系统上都是很常见的做法
-
这些控制器可以很不一样 但是实际上 大部分的工作方式是这样的
-
最低16KB空间 永远映射到Bank0
-
而16KB-32KB这部分可以映射到Bank1 Bank2等等
-
切换分页的方法就是往一个地址空间内写入一些特定数值
-
这些就会被MBC读取到 然后切换分页
-
这点对于外部RAM也是一样的
-
游戏卡带如果含有外置内存 比如用于保存游戏
-
比如装有备份电池的内存 这也是保存游戏的唯一办法
-
可以把外部内存映射在这里 一样的模型
-
所以这个BootROM是什么
-
CPU从内存地址0开始执行
-
BootROM的作用就是显示这些东西 然后响一声
-
BootROM是内置在GameBoy里面的
-
花了一段时间这些代码才被提取出来 还是挺麻烦的
-
(不是我完成的)
-
这个就是完整的BootROM
-
首先初始化RAM
-
初始化声音
-
设置和解码显示在屏幕上的logo
-
卷动logo 播放声音
-
然后就是有趣的部分 它对比logo
-
游戏卡带内需要有一份logo副本
-
如果两者不一样 就不会继续开机
-
这样任天堂就能控制什么游戏是给这个平台发行的
-
游戏必须要内置这个logo
-
如果未经允许加入 那不单单是违反版权保护 而且还是违反商标保护
-
最后是计算校验和 算是再一次确认
-
否则你得拆出来吹吹卡带 吹吹机子 重新插一遍
-
接着它关闭BootROM 继续执行
-
这个logo 实际上是从卡带里面读取并且显示出来的
-
如果不插卡带开机会看见这个
-
但是这并不代表游戏开发商可以往里面装入任何logo
-
因为GameBoy会对比这个logo
-
如果logo错误就不会继续启动了
-
因为没有清理代码
-
没有重启系统或者其它事情
-
所以有些游戏就直接开始调戏这个logo
-
直接在此之上继续
-
demo也显然很喜欢调戏这个
-
任天堂logo已经在屏幕上了 就对它做点啥吧(阴险
-
很不错
-
BootROM一直运行 直到最后一条指令关闭BootROM
-
这是即使是最低地址显示的也是游戏卡带的内容了
-
它就继续从这里执行
-
运行来自游戏中的下一条指令
-
通常这里是一个跳转指令
-
因为这其实是所谓的ROM头 按照要求就应该是这样的
-
头部必须内置任天堂Logo 头部校验和 这是很重要的
-
剩下的元数据就不重要了
-
对于当时的游戏开发者来说什么很重要
-
但是没有软件会真正检查这些内容
-
在这之后 就可以放真正的游戏数据了
-
还没讲到过的东西就是IO部分和HRAM了
-
也就是在最高页 所谓的第0页 可以比较高效得操作
-
最高的127字节是额外的内存
-
剩下的 就是这些不同的设备
-
这些是所有系统内的寄存器
-
中断控制器 声音控制器 摇杆输入 串口传输 定时器 还有PPU
-
这些就是要讲的所有东西
-
摇杆输入
-
非常简单 这是所有GameBoy拥有的输入
-
4个按钮 4个方向
-
于是你会想 弄8个GPIO 这样就能实现了
-
但是也可以用6个GPIO
-
2列4行
-
你选择想要测试的行 然后知道这一行按下了什么按键
-
这样就能用6个而不是8个
-
按键就是这些 很简单
-
串行数据传输
-
你可以用一条联机线把两台GameBoy连在一起
-
联机线其实就是 1条单向数据线 1条另外一个方向的数据线 1条时钟线
-
两台GameBoy得确定谁发送时钟 谁接收时钟
-
这些就是控制这些东西的位
-
一个设置输出时钟 永远是8kHz
-
接收时钟范围很宽 可以从0一直到0.5MHz都能收到
-
一旦传输开始 就会一位位移出字节 而且永远是全双工的
-
定时器
-
任何系统都得有个时钟 这个系统只有一个时钟
-
TMA寄存器用来存放计数初值
-
然后可以选择四种速度之一
-
接着打开定时器 向上计时
-
直到溢出 就会载入初值 然后可选的产生一个中断
-
讲到中断
-
中断控制器支持5种不同的中断
-
V-Blank(场消隐) LCD状态 也就是和PPU相关 一会讲
-
已经讲过的定时器 可以产生中断
-
串口 可以在接受到数据的时候产生中断
-
摇杆 可以在有按键按下的时候产生中断
-
这个是中断启用寄存器
-
一个中断标志寄存器
-
可以看见有哪些中断还没有被处理
-
这些是中断发生时会跳转的地址
-
你不需要手动确定发生的是哪个中断
-
因为直接跳转的就是不同的地址
-
所以 声音控制器
-
声音控制器的寄存器数量是最多的
-
一共有四个声部 每个声部有自己的一组独立的寄存器
-
这样看更为合理
-
4个声部 每个声部5个寄存器
-
每个寄存器有特定的含义
-
但是含义只是大致的
-
因为四个声道并不完全一样
-
有两个很接近的 产生方波
-
剩下两个一个是PCM采样 一个是杂波
-
看位定义的话 有一定相似性 但是还是不一样
-
具体通道有具体的定义
-
先看看共通的一些参数
-
每个声部都有一个开关位 也就是控制这个通道的开关
-
你可以在某个时候关掉这个通道
-
但是还有一个长度开关 以及长度设置寄存器
-
所以比如你可以这么设置 在0.25秒后自动关闭
-
然后先来看PCM采样声部的寄存器 也是最简单的一个
-
这个声部的作用就是 可以播放任何的波形
-
它有额外的16字节寄存器
-
里面有32个位置 每个4位
-
你可以在里面放任何你想要的波形
-
这里是几个例子
-
比如你可以产生一个锯齿波
-
算是相当基本的波形
-
也可以有正弦波
-
或者是任何自定义的东西
-
相当灵活
-
然后有一个频率控制
-
也就是控制采样的播放速度
-
2位的音量
-
音量可以在100% 50% 25%和静音之间控制
-
另外两个 是很相似的两个方波声部
-
这些位都是一样的,功能也一样
-
你不能指定波形 波形是固定的 只能是方波
-
就是只能是高或者低
-
但是高低比例(占空比)可以不同
-
这两个位就是控制占空比的
-
可以设置12.5%高 剩下的低
-
25%
-
50%
-
75%听起来应该和25%一样,只是反相了
-
这个是两个声部都支持的功能
-
另外有一个功能叫音量扫频 (Volume Sweep,翻译不准确,暂时想不到更好的)
-
就是音量可以增高或者降低
-
降低就是模拟乐器的情况
-
或者也能增高 效果比较有趣
-
然后 只有第一个声部有扫频功能
-
可以升高
-
也可以降低
-
所以可以注意到主要是用于音效的
-
更多的音效例子
-
这就是可以实现的效果
-
然后还有第四个杂波通道
-
就是一个只能产生伪随机数的移位寄存器
-
根据你设置的15bit模式或者7bit模式
-
他能产生两种不同的波形
-
这是15bit模式
-
这是7bit模式
-
这些是所有的寄存器
-
4个声部的寄存器 3个通用寄存器
-
这个可以设置左声道和右声道的音量
-
有趣的是卡带可以有自己的音频控制器
-
可以产生接到这个上面的音频信号
-
但是没有游戏做过这种事情
-
然后还有一个寄存器 可以设置一个通道是接到左声道还是右声道 或者都接、都不接
-
然后有一个电源开关
-
关掉音频部分可以减少约30%的电力消耗
-
然后 GameBoy的声音系统不单单被用于游戏
-
人们现在还在GB上用Little Sound DJ一类的软件编曲
-
我展示一个简单的例子
-
音频就到此为止
-
我们来谈谈Pixel Processing Unit (像素处理单元/PPU)
-
PPU就是产生图形的部分 拥有12个寄存器
-
并不是很多
-
首先来看看规格
-
在之前讲过,160*144像素,不是很多
-
4级灰度 其实更接近于4级不同的绿色
-
当然后续的GameBoy要好得多
-
所有屏幕上的东西都是以8*8像素的方格为单位的
-
屏幕上有一定数量的方格 还有一些精灵
-
这些东西都得装进8KB的显存
-
具体解释下这个8*8像素方格
-
我们看一下俄罗斯方块的游戏画面
-
所有东西都是基于这些方块的
-
塞尔达也是一样 画上网格线就能看见重复的图案 而且都是和网格线对齐的
-
超级马里奥大陆也是很明显 因为没有很多不同的方格
-
甚至是像Donkey Kong Land这样的游戏
-
在画上网格后还是能看出来的
-
可以看见重复对齐的图案
-
尽管他们很好地隐藏了这一点
-
有些游戏干脆就利用这个特性来设计
-
在Turrican里面干脆就用方块做了个动画
-
我们来看看方格是什么样的
-
一个方格尺寸是8*8 可以有4种颜色
-
4种颜色的编码就是00 01 10和11
-
把这个叠加到像素上看看编码是如何完成的
-
看第一行 直接当成一个二进制数读
-
于是就是 02 FF 一行像素需要2个字节
-
整个下来一个方块就是16字节
-
你可能注意到了这个颜色的排序比较奇怪
-
这是因为调色板是可以自定的
-
我可以选择任何想要的调色板
-
系统内对于这些背景方块有个2位到2位的映射
-
原生的表示方法是 00表示白 11表示黑
-
我可以选择任意的这种的调色板
-
如果有需要 我也可以选择一样的颜色
-
系统内一共支持256个方块
-
看这个设置 你认出是什么游戏了吗
-
这是俄罗斯方块
-
如果你不认识底部那些跳舞的人
-
说明你没有通关过俄罗斯方块
-
这是塞尔达
-
这是超级马里奥大陆 只使用了128个方块
-
有人认识这个吗?
-
这个只是一个拼图
-
是网球
-
20*18个方块填满了整个屏幕
-
但是其实事情不完全是这样
-
在视频内存中 有32*32方块
-
这才是完整的背景映射
-
屏幕上能看见的只是一个区域(Viewport)
-
256*256个像素还是相当方便的数字
-
卷动很方便,只要移动这个区域就可以了
-
使用这个模拟器就能很清楚得看到背景中发生了什么事情
-
以及可视区域是如何移动的
-
其实就像是一个摄像机,在32*32的映射中移动
-
但是这种方法只适用于最大地图只有32*32的游戏
-
但是那种需要无限卷动的游戏怎么办
-
比如超级马里奥大陆
-
最多可以有这么多的列
-
可以把区域移动到这里
-
但是到最后怎么办
-
它会直接卷到左边
-
如果我们能在显示出来之前重绘这些画面
-
就可以拥有无限的世界大小
-
在模拟器里就看得很清楚了
-
在屏幕显示不到的地方会不断刷新新的地图
-
对于二维也是一个道理
-
这是Donkey Kong Land
-
这个看起来很奇怪
-
只在需要显示的地方绘制新的地图
-
这是我们已经谈论过的一个图层
-
背景图层
-
除了背景外 还能放一层图像
-
窗口
-
可以直接覆盖
-
也可以放在任意地方
-
有个XY坐标
-
他会从起始坐标开始向右下方绘制
-
然而没有透明支持
-
通常的用法就是放到右边
-
或者放到下面
-
因为这个是不受卷动影响的
-
显然这个功能对于屏幕下方的分数显示来说是很必要的
-
对于游戏来说非常简单好用的功能
-
当然也能放在右边
-
这些是GBC游戏 但是不影响 在GB上也能玩
-
然后在背景和窗口层之上还有一个图层
-
就是精灵层
-
精灵就是放在屏幕上的不用受限于8*8方格的物体
-
可以自由摆放
-
现在屏幕上有3个精灵
-
任天堂把它们叫做 对象,OBJ
-
但是我还是继续叫他们精灵 因为就是精灵
-
就直接拿这个蘑菇举例吧
-
每个精灵都有自己的属性
-
系统内有个 OAM 也就是对象属性映射表
-
这个就是一个OAM记录
-
含有以下值
-
第一个是X位置
-
把它放到屏幕的左边
-
你可能会以为应该横向坐标为0
-
但是不是 是8
-
为什么呢
-
因为如果你把它放在4
-
他就在这
-
如果设置成0
-
那就看不见了 因为宽度是8
-
需要有一种方法能让它进入屏幕
-
对于屏幕顶端的情况也是一样的
-
但是你看现在的Y坐标是16
-
因为一个精灵最高可以有16像素高
-
把它放到一个自然的位置
-
下一个问题就是应该长什么样
-
首先看见是一个8*8的方格
-
和之前的方格是一样的编码
-
只是这个还带有透明色
-
所以00 表示透明
-
因为是一样的编码 所以也是一样的方格
-
而且系统内也有256个方格位可供使用
-
你看现在是方块编号0x90
-
剩下一个是 X翻转 选项
-
所以你没有必要为 向左走 和 向右走 的蘑菇单独存两个方块
-
水平翻转一下 就有向右走的了
-
垂直翻转一下 就有死蘑菇了
-
同时垂直和水平翻转 就有向右走的死蘑菇啦~
-
调回来
-
下一个是调色板
-
因为其中一种的颜色表示的是透明
-
所以只剩下3种颜色可以选择
-
他们不想强制固定这三种颜色
-
所以你可以在四种颜色里面挑3种想要的
-
而且不同的精灵不需要使用同样的3种颜色
-
因为系统内可以有两个调色板
-
所以才有这个位 可以选择是调色板0还是调色板1
-
调色板1和0分别效果就是这样
-
剩下一个是优先级
-
就是精灵碰到背景时如何绘图
-
如果优先级是1就有趣了
-
它会画在这些白色像素之上
-
但是在所有不是白色的像素后面
-
当然白色并不是一个什么特殊颜色
-
只是指背景调色板里的0号颜色
-
所以改调色板 就能让蘑菇显示在任意颜色之上
-
优先级0的话就会绘制在任何东西之上
-
当然不包括透明像素
-
然后就是精灵之间的优先级问题
-
这个没有办法自己设置
-
这个是固定的
-
现在蘑菇在正方形之上
-
因为它的横向坐标比正方形小
-
一旦达到一样的坐标
-
精灵编号小的显示在上
-
因为精灵在内存中也是一个数组 存前面的画上面
-
然而一旦正方形的X坐标小于蘑菇的X坐标 就会画在上面
-
一部分游戏中穿透其它精灵的时候 就能看到这种现象
-
系统支持最多40个精灵 屏幕上最多也是能放40个
-
但是还有一个限制
-
每一行最多只能有10个
-
比如这里有11个
-
10个是按照一行像素计算的
-
所以这些像素就不会被显示出来
-
或者是下面两行
-
这个不是讲从左到右的第十个
-
而是按照精灵的编号来决定的
-
所以这是一个完整的OAM记录
-
一共4个字节
-
这是内存中的一个OAM记录
-
FE00就是存储这些记录的起始地址
-
一共有40个记录 里面能存40个精灵
-
整个这个叫做OAM内存
-
就是一个存在这个位置的专用内存
-
并不是显存的一部分
-
还有一件事情
-
就是即使是小马里奥
-
也超过了8*8
-
你可以用4个精灵来实现
-
这也是游戏里的做法
-
但是还有一个模式
-
可以拥有16像素高的精灵
-
但是这个设定是全局的
-
整个游戏都得使用16像素高的精灵
-
所以已经见过3层了
-
还有一件事情是 屏幕是可以被彻底关闭的
-
这样就有第五种颜色了(强行)
-
稍微比白色位再淡一点
-
没啥用 因为得把屏幕关掉
-
一旦打开屏幕但是不画任何东西
-
就是白色
-
然后打开背景层 比如说要显示个淡灰色
-
然后就完全代替了这个颜色
-
再画个窗口
-
注意没有透明
-
还能在上面画精灵
-
但是注意精灵和窗口的颜色就无法区分了
-
所以说窗口上没有裁剪一类的事情
-
所以内存映射是怎么样的
-
4KB的精灵方块
-
4KB的背景方块
-
1KB的背景映射表
-
32*32
-
1KB的窗口映射表
-
这不是最高效的表示方法
-
但是他们这么做了 因为方便
-
但是我们只有8KB的显存
-
放个精灵方块和背景方块 就用完了
-
换种方法
-
先放上精灵方块 然后在最后放上背景和窗口映射
-
背景方块怎么办
-
就让它们重合
-
有不同的配置 3个位
-
可以让它们完全重合
-
也可以只重合一部分
-
这些也可以交换或者重合
-
重合表示什么意思
-
这个情况就是精灵方块和背景方块完全重合
-
可以共享完全相同的方块
-
但是也可以这么放
-
前128个就是精灵专用 后128个就是背景专用
-
中间128个共享
-
比如这个超级马里奥大陆
-
前2/3都用于精灵了
-
剩下的1/3被用于背景
-
下一个部分是横向计时
-
在基于CRT的机器当中
-
这就是CRT显示图像的慢动作效果
-
从头到底 从左到右
-
对于GameBoy也是一样的
-
它以60Hz的速度不停地扫描
-
从上到下 一行一行
-
从左到右
-
这不是因为使用了一些旧的器件
-
他们完全重新实现了这一部分的内容
-
但是液晶本身就需要以60Hz的速度刷新
-
所以就这样了
-
如果要实现一些特效的话是很重要的
-
比如这个游戏中
-
屏幕不同的区域行为是不一样的
-
比如我们先只看这个滚动的城市图
-
直接全屏滚动肯定是不成问题的
-
但是我们只想让它在屏幕上的一部分滚动
-
就可以通过这些额外的寄存器完成
-
如果你之前接触过8位机的编程 比如C64什么的 那么应该会理解
-
你可以知道当前正在画哪一行
-
或者马上会画哪一行
-
除了一直等着 还可以设定一个中断
-
一旦到达某一行就会执行特定代码
-
我们先把SCX寄存器设定到0
-
然后在第8行触发
-
所以它就会以卷动为0的参数显示出这些
-
然后现在我把横向滚动 设置成比如23 然后下一帧设置成24 这样就能滚动了
-
把对比寄存器设置到42 就会一直继续绘图到42行
-
设置成其它的 再修改LYC 画完这个路面 一会具体讲路面的事情
-
最后再设置回0 因为仪表盘不需要卷动
-
下一帧也是同样这么处理
-
这个例子中就不需要修改X卷动寄存器了
-
这个例子中 右上角的马里奥其实是一个窗口
-
我们在之前讲过 窗口会从左到右从上到下绘图
-
本身并不能这样只停在右上角
-
但是可以做到
-
在第0行触发中断 启用窗口
-
在第40行的时候再触发中断 关闭窗口
-
于是在40行的时候 PPU的情况就是:“窗口?啥子窗口?没听过这个说法”
-
于是就不会继续画
-
这个方法在不同的游戏中都有应用
-
一些是关于窗口,一些则是和卷动有关
-
但是如果你不是在一个特定行触发
-
而是每一行都触发的话 就能实现一些比如这样的效果
-
左边是屏幕上的效果
-
右边是实际上存储在显存中的数据
-
如果你在每一行都改变卷动寄存器
-
比如按照这个曲线调整
-
那么就能实现对图像的变形
-
然后每一帧都改变这个曲线
-
程序要做的就是 在每一行都向SCX写入一个值
-
当然如果图片每行都显示那就每行都得修改
-
而这个赛车游戏的效果其实差不多也是一样的道理
-
这是视频内存中的情况
-
只是一条直的路
-
但是在绘图的时候被扭曲
-
放大这块
-
这是原始数据 这是效果
-
忽略这里的精灵
-
这是为了扭曲需要的曲线
-
这是需要的偏移 也就是SCX
-
如果你每行都调整SCX 就能扭曲成这样
-
另外一件事情就是
-
路中间的线变成了虚线 路外部也有一些横线的图案
-
这是通过每几行就调整调色板来实现的
-
如果看这个游戏的话 甚至可以实现弹跳的效果
-
这是通过在每行同时调整纵向和横向卷动寄存器实现的
-
所以就可以重复一行的内容或者跳过某些行
-
只要计算好 就可以实现这种效果
-
只要在行中修改垂直卷动寄存器
-
就能实现二维的扭曲效果
-
但是我们还得再仔细讲一讲 横向计时
-
在一行绘制的时候 发生了什么
-
这是PPU的像素传输模式
-
通常需要43个时钟的时间
-
一共144行
-
但是你不能直接认为
-
在第一行结束后 它会立即绘制下一行的第一个像素
-
现实不是这样的
-
因为在每一行的开始还有一个OAM搜索阶段 需要20时钟
-
我一会讲
-
每行的结尾还有一个51时钟的行消隐
-
在行消隐阶段,PPU就闲着,什么事情都不做。
-
还有一个场消隐阶段 就是在帧之间的空闲
-
来计算一下
-
一行有114时钟 频率是1MHz
-
154行 所以需要这么多个时钟周期完成1帧
-
如果以用基准频率除以这个
-
得到的就是59.7Hz的刷新率
-
PPU当前所在的状态是可以直接读出的
-
CPU可以知道 而且也可以基于这个设定中断
-
但是CPU为什么需要知道呢
-
我们来看看不同模式下都发生了什么
-
首先 每行开始20周期的OAM搜索是做什么的
-
每一行 PPU都需要确定这一行中哪些精灵是可见的
-
所以系统内一共有40个精灵
-
然后它得找出 这一行中可见的精灵
-
然后放进一个最多可以保存10个精灵的 可见精灵数组
-
逻辑是 x坐标不能为0 因为那样就不可见了
-
然后当前所绘制的行必须要在精灵的第一行和最后一行之间
-
符合要求就加入可见精灵数组
-
然后这需要20周期的时间
-
顺便在原版的GameBoy中这里有个有趣的bug
-
如果你在OAM搜索期间 进行了任何数字在FE00到FEFF之间的16位运算
-
也就是到OAM内存的指针
-
即使你没有访问内存
-
他也会破坏这一块的内存
-
还有什么需要注意的
-
CPU连接到内存
-
PPU连接到显存
-
OAM内存是特殊的 PPU也直接连接到OAM内存
-
CPU也可以连接到显存 这样就能写入到显存
-
但是并不是这样完成的
-
那样需要双倍速的显存
-
你看C64是那样做的 但是在GameBoy上就必须经过PPU
-
PPU内部有个开关 PPU可以决定CPU能不能访问
-
如果PPU不让CPU访问
-
那么CPU进行写入 什么都不会发生
-
CPU进行读取 读到的全部是FF
-
至少不会发生什么严重的问题
-
但是也没有什么意义
-
所以说CPU必须确保PPU在合适的模式下 这样才能顺利访问
-
在像素传输阶段 不能访问显存
-
但是在OAM搜索 行消隐和场消隐阶段都是可以访问的
-
如果你想要访问OAM内存
-
OAM搜索或者像素传输都不可以
-
像素传输时PPU要绘图 需要精灵数据
-
只能在这些时候才能访问
-
所以在屏幕绘图时就得十分小心
-
所以这些时间对于CPU来说都是不好的
-
不应该做任何重要的事情
-
比如说CPU想要把新的一行移动进背景映射
-
最好是在场消隐阶段完成
-
有最多的不被打断的时间
-
而所有的游戏逻辑和AI可以在屏幕绘图的时候完成
-
但是这个时候不能立即写入新的精灵位置
-
因为OAM也是不能访问的
-
所以游戏一般的做法都是
-
把新的精灵信息全部写入一个OAM内存的副本
-
然后在场消隐阶段复制进OAM
-
就是从任何这里其中一个 存放OAM副本的地方
-
复制进OAM 这个图不是按比例画的
-
而且这个过程不需要自己完成
-
有一个DMA功能
-
写入想要复制的块
-
然后等待160个时钟
-
在复制的过程中 CPU还是在运行的
-
但是不能访问任何的源地址空间
-
所以只能等着
-
但是因为这个代码也得有地方存放
-
所以可能的地方只有是HRAM
-
也算是个不错的用途
-
然后是像素流水线
-
我们继续深入来研究像素流水线
-
这个还算是非常新的研究 之前是没有公开的
-
像素FIFO(先入先出缓存)是GameBoy绘图的核心概念
-
我们直接跳到中间过程
-
屏幕上已经有一些像素了
-
比如这5个像素已经被送给LCD了
-
然后像素FIFO 里面有一些像素
-
然后每一个4MHz的步骤 它都会移出一个像素
-
送给LCD
-
移出一个像素 送给LCD
-
然后再移出下一个给LCD
-
你可能注意到那个绿色的指示灯变成红色了
-
因为像素FIFO必须要有至少8个像素才能移出像素
-
为什么 一会会讲到
-
现在需要产生新的数据来填充FIFO了
-
Fetch(获取)单元就是做这个的
-
它会读取背景方块单元
-
9802是目前在读取的映射位置
-
它从背景映射中读取方块的ID 需要1个周期
-
然后从方块数据内存 读取第一部分和第二部分的数据
-
因为每一行的方块是16位
-
这样它就能产生8个新的像素
-
然后就重新开始 进入下一个位置
-
就可以把这8个像素移入FIFO的上半部分
-
这样就可以继续移出新的像素
-
然而在执行过程中
-
并不是说等待有空了 然后开始Fetch填充 移出再这样
-
并不是交替进行的 而是同时进行的
-
FIFO是2倍速的
-
所以Fetch进行1个步骤 FIFO移出两个像素
-
移出 移出 读取第一字节的数据
-
移出 移出 读取第二字节的数据
-
然后到这个时候
-
现在还不能把数据存入FIFO
-
因为FIFO还放不下
-
所以Fetch先关闭
-
等待2个周期
-
也就是空闲一段时间
-
然后放入数据
-
所以如果你看内存访问的模式
-
就能看见3次读取 1次空闲 3次读取 1次空闲这样
-
所以 FIFO就是4MHz时钟下 每个周期移出一个像素
-
除非含有超过8个像素 否则暂停
-
Fetch单元 运行频率是2MHz
-
需要3个周期来获取8个像素
-
然后在第四周期停住 直到FIFO有空位
-
横向移动的实现方法非常简单
-
比如说我们移动3个像素
-
所以所有东西都向左移动了3个像素
-
最先的3个像素就直接无视掉了
-
然后下一个像素送往LCD
-
而在行的最后
-
事情变得有趣了
-
因为我们想在X=160的时候触发
-
FIFO可能还包含一些根本不会被画出来的像素
-
然后Fetch可能也已经在获取下8个像素的内容了 也不要了
-
然后就全部停止
-
就是干了太多活了 直接进入行消隐
-
这也是一行需要43周期 而不是40周期的原因
-
如果我们开启了窗口
-
比如说窗口坐标是26
-
我们现在就在26 然后FIFO已经缓存了一些像素了
-
它会完全清空FIFO
-
然后FIFO会被停止
-
因为这些像素已经不需要了
-
然后Fetch会被转到窗口映射
-
然后Fetch被重新开始
-
然后还是一样 读ID 读两个字节
-
就得到了窗口的数据
-
然后就可以放入像素FIFO
-
只要这些开始被移出了 窗口就绘制出来了
-
而精灵则是有10个比较器
-
也是根据X位置触发
-
比如说在这里X=26有一个精灵
-
一样 像素FIFO里面有很多像素 然后Fetch执行到一半
-
首先我们暂时暂停像素FIFO
-
就不能继续移出新的像素
-
然后暂时调整Fetch让它产生精灵数据
-
重新开始Fetch
-
然后就得到了精灵数据
-
然而这次不是放到最后
-
而是和前8个像素叠加
-
混合到已有的像素上
-
这也就解释了为什么FIFO中必须要有至少8个像素
-
因为精灵是用这种方法来混合的
-
然后和其它的系统有一个区别
-
在窗口开始前 都以恒定速度移出像素
-
当窗口开始的时候
-
FIFO被清空 很长一段时间都不能输出数据
-
直到FIFO内有了窗口数据
-
也就是等到恢复了
-
也就是需要至少43个周期
-
如果有精灵就需要更多
-
在基于液晶的系统上这么做是完全可行的
-
你可以暂停发送像素
-
而在基于CRT的系统上 不行
-
比如说在C64上
-
一行必须是正好的40时钟
-
因为任何晚出来的像素看起来都会被右移
-
所以这个图并不是完全准确
-
像素传输应该是至少43时钟
-
行消隐则是剩下的时间
-
然后实际过程中 取决于屏幕上的内容 更接近于这样
-
但是之前这个并不是像素FIFO真正的工作方式
-
它并不存储像素颜色
-
它存储的是原始的位组合
-
以及来源
-
比如说这里是9个背景像素
-
Fetch也是一样的
-
它并不产生像素颜色
-
它产生的是位组合
-
加上来源或者精灵调色板
-
我们来把这个混合一下
-
精灵的00表示在背景之上绘图
-
来过一遍
-
这里是精灵调色板1 数据00 表明是透明的 背景获胜
-
这个情况下精灵获胜 因为应该画在背景之上
-
大部分像素都是这个情况
-
而最后这个像素 是精灵调色板1 数据透明 所以背景获胜
-
再来和同一坐标下另外一个精灵混合一下
-
这里是精灵调色板0 在背景之上 精灵获胜
-
然后这个情况下 新的精灵不会覆盖旧的
-
所以旧的获胜 然后就一直这样
-
这也就是精灵会画在右边精灵的上面
-
但是不会画在已有精灵之上
-
高ID精灵输给低ID精灵的原因
-
最后这里新的精灵又获胜了
-
然后应用上调色板
-
只有在最后像素被移出的时候才进行
-
这里对应调色板 移出一个像素到液晶
-
查表 转换 LCD
-
另外一个 黑色
-
这也是在彩色机型上的做法
-
从SGB开始
-
现有的游戏不能处理颜色 但是可以上色
-
然后就是 已有的三种调色板现在变成了RGB调色板
-
其它所有的都是一致的
-
但是一旦移出像素
-
它就对应RGB颜色
-
把这个粉色的像素显示在屏幕上
-
S1 11是这里
-
黑色像素
-
再来一个例子 S1 01 精灵调色板1 显示在屏幕上
-
所有技术性内容到此为止
-
还有5分钟的时间
-
来讲讲开发
-
如果你对GameBoy开发感兴趣
-
有一些很不错的开发工具
-
Rednex Game Boy 开发系统是一套命令行工具
-
可以配合自己的编辑器和Makefile使用
-
如果想要Debug
-
BGB模拟器 就很不错
-
为Windows设计 但是配合Wine在OSX和Linux上也没问题
-
内置调试器 断点啊 单步啊 一类的
-
然后还有一个显存查看器 可以查看所有发生的事情
-
很适合在上面运行Demo然后观察发生了什么
-
如果你想要在真机上运行
-
也有像Everdrive一类的设备
-
可以插SD卡
-
因为还有4分钟时间
-
我们来谈谈我最喜欢的GameBoy外设
-
Game Boy Camera
-
但是不是技术层面
-
只是吹一波这个设备
-
这个就是Game Boy Camera
-
你把它插入GameBoy
-
能拍照片
-
然后可以用Game Boy Printer打印出来
-
用的热敏纸
-
如果还买得到的话
-
然后可以拍出像这样的照片
-
放大一点
-
非常棒的照片
-
每张照片 都是用这个14K像素的CCD拍出来的
-
位深2位 (译者注:硬件为3位,抖动为2位以匹配GameBoy屏幕)
-
所以下次去旅游的时候 记得带上GameBoy
-
然后还有Game Boy Camera 加上一台带并口的PC 还有已经买不到的联机线
-
所以感谢这些人 研究GameBoy 以及帮助我准备这场讲座
-
这些人也是以各种途径帮助了我
-
所以
-
在这个系列中 这已经是第五场讲座
-
下一个是什么
-
明年应该有个讲座吧
-
我建议两个讲座
-
我就先给34C3几个提名
-
Dominik Wagner来讲Acorn Archimedes
-
然后Jannis Harder来讲SNES
-
这是你们自己的选择 可以做这些讲座
-
或者也可以在自己头上倒冰水
-
感谢参加 明年见
-
subtitles created by c3subtitles.de
in the year 2017. Join, and help us!