我暂时不直接讲FC具体开发过程,而是打算慢慢介绍FC系统的开发思路。

如果直接从具体代码开始,会让读者有“身在此山中,不识真面目”的感觉;当然也不能脱离代码,空谈架构,失去了本系列的意义。

希望这种介绍方式能让大家逐步理解早期游戏主机与现代PC系统的巨大差异,能够感受到在2021年研究FC的乐趣。

1、为游戏而生的硬件系统

FC红白机,从技术本质上看是一台简易单片机系统。

它具有一个核心CPU,以及较小的内存(内存可以集成在CPU内,也可以外置)。
在电路板上包含一些外围电路和芯片,外围芯片一般负责输入输出、声音播放、内存扩展等。
CPU和外围电路之间通过已经焊死的线路进行通信。只要写特定的汇编指令,就能和外围电路通信发送、接收数据。(读者不要怕,只要调用C函数就行)
整套系统中,没有操作系统,没有内存管理。只要一插电就会按预定方式运行。所有变量和内存一开始都要安排好内存位置。
CPU会忠实的一条一条执行程序指令,没有报错机制、没有异常处理,就和一台机械钟表一样严格运行。
如果代码写错,可能会黑屏、花屏、死循环等等。但从底层视角看来,一个游戏花屏了和正常运行也没什么区别,一样都是运行状态。
不用考虑程序如何停止,CPU会这样永远运行下去,直到断电。
按理来说,一台像这样主频仅有1.8Mhz,内存2KB的单片机,不可能实现《超级玛丽》、《魂斗罗》这样丰富多彩的实时游戏。

但FC就做到了,关键技术有两个,一是外围有专门的显示芯片(PPU,可以直接向电视机输出信号,含2KB显存);二是软硬件紧密结合,做到没有“游戏引擎层”,争取不浪费任何一点性能。

FC的软硬件结合有多么紧密呢?就连“1.8Mhz”这个CPU频率都与FC的显示分辨率相关。频率差一点,连显示都会错乱。

比如,旧的彩色电视标准有两套:欧标PAL和美标NTSC,二者的显像管刷新频率不同。FC如何兼容两套标准呢?

答案是:不考虑兼容。生产两种不兼容的主机,负责显示的PPU型号不同,连CPU也略有区别。

美国NTSC制式 日本PAL制式
CPU 2A03 @ 1.79MHz 2A07 @ 1.66MHz
PPU 2C02 @ 5.37MHz 2C07 @ 5.32Mhz
电视信号频率决定了PPU频率设计,而CPU频率必须照顾PPU频率。三者就是这样的连带关系。

频率正确时,正好能保证PPU每刷新一行正好是CPU的一个周期。这样就不用添加额外的定时系统。

这种硬件更像是一套精密的机械结构,牵一发而动全身,几乎没有智能性。


CRT电视机内部。前面是屏幕,一个像素被电子束打到会发亮。后面是一个高速扫描的电子发射器。
在开发的过程中,虽然我们写的是C语言代码,但是大脑中还要记得有一个PPU正在与代码协同工作。理解这一点对理解时序问题比较重要。

2、1984年的游戏开发环境

其实FC硬件定稿时,包括开发团队本身在内,所有人对于FC游戏到底怎么写、硬件机能到底有多高、音频芯片怎么用、PPU怎么用,只有很粗浅的认识。

比如说,FC具有完善的“背景卷动”机制。但最早的《大金刚》、《大力水手》等游戏,大都采用固定版面。

FC早期任天堂自己推出了《马里奥》一代,是当年绝对的划时代大作,逼真的物理效果、背景卷动等FC功能基本都用到了,给后来者做出了示范。

我想说的是——你可以将FC看成一套简陋而没什么规矩的游戏引擎,很多高级功能的实现,依靠的是程序员的聪明才智,将简陋的硬件水平发挥到极致。

(比如《马里奥3代》中的大部分功能,在早期都是不可想象的高科技。举个例子,这游戏竟然可以同时上下左右背景卷轴??!!硬件根本就没提供这个功能。)

但老任的技术不是那么容易学会的,当年可是基本软件极度缺乏、也没有互联网的年代,那时候的技术文档写得晦涩难懂,而且即便是烂文档都非常稀缺。不仅FC的开发机要花重金购买,买来还得自己死磕研究。那时候的开发环境之恐怖,连1970年代出生的开发者都很难想像。

就算南梦宫这样的名厂也得死磕技术文档,从《吃豆人》做起,慢慢积累慢慢研究。

不过,当年的开发者也有一点与现在不同——现代开发者属于纯软件开发者,对硬件知之甚少。而当年所有的程序员都略懂硬件,二进制、单片机、汇编对他们来说属于基础知识。

所以,对我们很难的地方对他们来说可能没那么难。

3、FC硬件架构

下图是我翻译的FC硬件架构图。来源:NES Hardware Explained


主要的芯片模块图中已经标的很清楚了。

值得说明的是,FC卡带在插上以后,其实已经成为了整个系统的一部分,所以原理上就不可能实现“热插拔”卡带,玩游戏过程中拔卡必然会死机;换卡之后必然要重启系统。

从原理上看,卡带并非软件,而是硬件的一部分。

后期游戏为了增强功能,还在卡带中添加了专用芯片、附加显存、附加存档区域等等,可以看成一个“子系统”。

本期先到这里,下一期我将介绍FC的游戏引擎主循环写法。