日常讲屁话
吃得饱,打算写个 NES emulator,语言使用 Swift(一边看文档一边学),目标是做个 macOS App,如果有人有想法,把它移植到 iOS 上也可以。macOS App 开发也是临时看文档学,代码质量估计不高,先这样吧。
NES:是 FC 主机欧美地区发售的称呼。1985年10月,NES 正式在西方国家推出,除了名称由 Family Computer 改为 Nintendo Entertainment System,造型设计也大幅改变。我们 80/90 后都玩过的小霸王就是内置了一个 NES,比较出名的游戏如超级马里奥,我们的大目标就是可以仿真运行一个超级马里奥初代。
设备结构
开发一个 NES emulator 之前,我们来过一遍 NES 的主要组成部分。基本上有这些模块

- CPU NES 的处理器是 MOS 6502 的衍生产品,譬如 Apple II 的处理器就是它这一系的,这是我在网上找到的一篇关于该处理器的文章 MOS Technology 6502 CPU。我读中学的时期,国内有一些低端学习机(譬如电子词典这类)用得也是这个 CPU,具体可以查一下,此处不赘述。它是一个 8 位的处理器,频率是 1.7897725MHz(通常是 NTSC 机型, PAL 机型下频率只有 1.773447MHz),中断模式有 RESET、NMI、IRQ。
- PPU 这个全称是 Picture Processing Unit,这玩意是用来处理图形的。它会把图像用 256 * 240 的分辨率输出(受限于 NTSC 上下各 8 行显示不了,其实只能显示 256 * 224),调色盘可显示 48 色 5 个灰阶(现在看起来好像蛮弱的),NES 中图像分 Background 跟 Sprite,通过组合两者来显示完整的图像。如果你尝试开发过 Game Boy 的小游戏, 你会发现这两个概念好眼熟,因为受限于那个年代游戏机平台的硬件机能,很多 2D 游戏机是通过类似方式处理图像的(Sprite 在 Web 前端应用或小游戏开发里也有相应的应用)。
- RAM NES 的 CPU 跟 PPU 都有 2KiB 大小的内存
- APU 是一个音频处理器,全称 Audio Processing Unit,这个模块其实集成在 CPU 中, 所以它并不是独立的芯片,可以称它为 p(seudo)APU,它提供了五个通道用来处理音频,分别是两个矩形波通道,一个三角波通道, 一个噪声波通道(譬如爆炸声),一个音频采样通道(主要用于处理背景音)。
- 卡带 由于 NES 没有操作系统,所以内容由卡带提供,每个卡带至少包含两个东西,一个是 CHR ROM 主要用于存储游戏图形的数据,另一个是 PRG ROM,主要是用来存储游戏的指令。现实中卡带插入到机器后,CHR ROM 直接连接到 PPU,PRG 连接到 CPU,NES 后续的机器还用卡带提供其他的扩展,不过目前我们先不太深究这块内容
- 手柄 这就是个输入设备就不细讲了
其实这些就是我们的目标,我们要把这些模块都用代码描述出来,由于我们用得是高级语言,所以很多东西都变得简单起来了。
创建项目
现在来启个新项目,具体怎么创建 macOS 项目就不截图描述了,我就不用 SwiftUI 模板创建项目,因为我只想要显示一个窗口,输入相关也是通过键盘处理,界面上也没有太复杂的 UI,然后把 AppDelegate 类改一下
import Cocoa
@main
class AppDelegate: NSObject, NSApplicationDelegate {
var window: NSWindow?
func applicationDidFinishLaunching(_ aNotification: Notification) {
window = NSApplication.shared.windows.first
window?.title = "NES emulator"
window?.setFrame(CGRect(x: 0, y: 0, width: 960, height: 544), display: true)
window?.center()
}
func applicationWillTerminate(_ aNotification: Notification) {
}
func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool {
if !flag {
for a in sender.windows {
if let w = a as NSWindow? {
w.makeKeyAndOrderFront(self)
}
}
}
return true
}
}
现在第一步已经处理好,后续水文主要专注写 emulator 的逻辑,再把仿真后的内容展示在窗口上。
评论 (0)