本系列文章将构建一个Chip-8系统的模拟器。
如果您已经对Chip-8感兴趣,或者想学习模拟器的工作原理,这是一个很好的起点。
如果您对模拟器比较熟悉,并且想了解更复杂的系统,可以查看我们的NES系列文章。
Chip-8是一个非常简单的系统,但拥有与更复杂系统相同的所有组成部分。这为学习数字系统和模拟器提供了一个很好的小型项目。现在让我们深入了解一下。
**关于Chip-8**
Chip-8能够实现您在典型视频游戏系统上看到的大部分功能,包括:
* 运行程序
* 图形
* 声音
* 输入
* 计时器
我们最终会涵盖这些功能中的每一个。首先让我们看看系统如何运行程序。
**在Chip-8上运行程序**
Chip-8,就像一个物理CPU一样,旨在执行程序。程序是一个精心挑选的指令列表,这些指令组合在一起以实现某个目标。
可以将指令视为计算器上的一个操作按钮。每个指令执行一个基本操作,可能涉及一些输入数据。可编程系统的关键在于,每个指令都被表示为一个数字。系统有一种方法可以运行这些指令(就像计算器一样),但它也有一种方法可以查看程序并决定要按下哪个“按钮”。
我们稍后将了解如何运行程序,但首先快速介绍一下计算机数字。
**数字基础**
为了更好地理解Chip-8程序的布局,我们需要了解计算机如何表示数字。如果您已经了解二进制和十六进制,可以跳过本节。
**二进制数**
计算机擅长以两种不同的形式存储信息。我们可以称之为是和否或真和假。这影响了计算机如何表示数字。人类有10根手指,因此我们最终使用了以10为底的数字系统。
多位数中最右边的位置的值为1。向左移动,每个值都比前一个值大10倍。
计算机使用以2为底,或“二进制”。最右边的位置的值仍然是1,然后每个位置的值都是其右侧位置的2倍。
因此,在十进制(我们的以10为底):
123 = 1*100 + 2*10 + 3
如果我们要用二进制表示它,它将是:
1111011 = 1*64 + 1*32 + 1*16 + 1*8 + 0*4 + 1*2 + 1*1
为了区分不同基数的数字,我们通常在二进制数前加上“0b”前缀,以告诉我们它是在以2为底表示的数字。
虽然二进制数对计算机来说很方便,但对于人类来说有点笨拙。它们占用大量空间,并且容易打错或读错。也许中间有折衷方案?
**十六进制数**
在实践中,当谈论计算机数字时,我们通常使用以16为底,或十六进制。有时缩写为“hex”。在这里,每个位置的值都是其右侧位置的16倍。
十六进制的一个障碍是,我们需要16个不同的符号来表示每个位置。我们可以从十进制中借用0到9,但需要额外的符号。为了解决这个问题,我们使用拉丁字母的前6个字母(ABCDEF)。就像二进制一样,当编写十六进制数字时,我们可以使用“0x”作为前缀,以表明这些数字是以16为底。
一些示例以帮助澄清:
| 十进制 | 十六进制 |
| -------- | -------- |
| 0 | 0x0 |
| .. | .. |
| 9 | 0x9 |
| 10 | 0xA |
| 11 | 0xB |
| .. | .. |
| 15 | 0xF |
| 16 | 0x10 |
| 17 | 0x11 |
| 123 | 0x7b = 7*16 + 11 |
十六进制很好,因为它表示与二进制相同的块信息。我们可以将十六进制视为编写二进制的简写。十六进制中的每个符号(有时称为半字节)保存4个二进制数字(或位)的值。
再次查看我们的123示例,我们可以看到
123十进制 =
0b 0111 1011
在前面加上一个零以确保我们有完整的4组。
然后我们将每个表示为一个十六进制数字。
1011 = 8+4+1 = 11 = 0xB
0111 = 4+2+1 = 7 = 0x7
这给了我们123 = 0x7B,正如我们预期的那样。这就是我们如何快速在十六进制和二进制之间转换。
十六进制还有一个方便的功能。计算机倾向于将位分组为8位。我们称之为字节。字节的值很容易用十六进制表示,用两个十六进制数字。
现在我们准备开始查看一些Chip-8指令了!
**Chip-8指令**
在Chip-8的维基页面上,您可以找到系统的“操作码表”。“操作码”是系统所知道的所有指令的数字表示。
此表告诉我们如何表示系统的命令或指令。在这里,我们会发现我们的十六进制知识很有用。
查看第一个指令之一,我们看到:
| 代码 | 功能 |
| ----- | ----------- |
| 0x00E0 | 清除显示器 |
这仅仅意味着当系统正在查看指令时,并且偶然发现了0x00E0,它将清除屏幕的内容。完整的操作码表包含更复杂的指令和操作码表示。我们下次将同时查看两者,并开始编写一个基本的Chip-8模拟器。