---
schema_version: "library-reader-v1"
source_type: "original_book"
title: "编码 隐匿在计算机软硬件背后的语言"
author: null
edition: null
publisher: null
year: null
isbn: "9787121181184"
library_document_id: "38270854-596f-4a26-8183-db8c968c6020"
source_sha256: "249786274d83909f0bddc34d77f81ed8f0b14d1eac8843c772a37a3ecbfe2cfc"
pdf_physical_page_count: 438
pdf_physical_page_index_base: 0
range_start: 290
range_count: 10
html_url: "https://workshop.closeclaw.top/api/ai/read/38270854-596f-4a26-8183-db8c968c6020?start=290&limit=10"
markdown_url: "https://workshop.closeclaw.top/api/ai/read/38270854-596f-4a26-8183-db8c968c6020.md?start=290&limit=10"
previous_url: "https://workshop.closeclaw.top/api/ai/read/38270854-596f-4a26-8183-db8c968c6020.md?start=280&limit=10"
next_url: "https://workshop.closeclaw.top/api/ai/read/38270854-596f-4a26-8183-db8c968c6020.md?start=300&limit=10"
---

# 编码 隐匿在计算机软硬件背后的语言

> 页码规则：PDF_PHYSICAL_PAGE_INDEX 是从 0 开始的权威文件物理页索引；PRINTED_PAGE 是页面中识别出的印刷页码，可能为空，二者不得混用。

## PDF_PHYSICAL_PAGE_INDEX=290 | PRINTED_PAGE=274

英特尔在为日本吉康（Busicom）公司生产的可编程计算器设计芯片的过程中，决定采取一种不同的方法。正如英特尔工程师特德·霍夫（TedHoff）说的：“我想让它成为一个具有通用功能的计算机，进而可以通过编程成为一个计算器，而不是使这个设备成为一个只有一些编程能力的计算器，”这导致了Intel4004的产生，它是第一块“计算机芯片”，或者叫做“微处理器”。1971年11月，4040芯片已经可以得到使用，它拥有2300个晶体管（依照摩尔定律，18年后微处理器包含的晶体管数将是这个数字的4000倍，或者说是1000万。这是一个相当精确的预测)。

我们已经知道4004芯片包含的晶体管数目，下面是4004芯片另外三种重要的特征。自4004芯片开始，在比较微处理器性能时，通常采用三个衡量标准。

第一个标准；4004是一个4位微处理器，这意味着处理器中数据通路宽度只有4位。每次做加、减运算时，它只能处理4位的数字。对比来看，第17章中的计算机数据通路是8位，因此被称为8位处理器。我们即将看到8位处理器很快就超越了4位处理器。但技术并没有停止于此，20世纪70年代末期，16位微处理器已经得到了应用。回想一下第17章中的内容，以及在8位处理器中进行两个16位数加法所必需的指令码，你就会欣喜地发现16位处理器带来的优势。到20世纪80年代中期，32位微处理器诞生了，并自此一直作为家用计算机的主要处理器。

第二个标准：4004每秒最大时钟频率为108,000周期，即108KHz。时钟频率是指连接到微处理器并驱动它运行的振荡器的最大频率，超过此时钟频率，微处理器将不能正常工作。到1999年，家用计算机的微处理器已经达到了500MHz比4004要快5000倍。

第三个标准：4004的可寻址存储器只有640字节，现在来看这个数字小得有点荒唐，但这与当时可得的存储芯片的容量是一致的。下一章中你将会看到，两年之中微处理器的寻址能力就达到了64KB，与第17章中计算机的能力比肩。1999年英特尔生产的芯片可以寻址64TB的空间，尽管当时多数人的家用电脑RAM容量还不到256MB。

上述三个数字指标并不能影响一台计算机的计算能力。比如，4位处理器同样可以实现32位数字加法，只不过是将其简单拆分为4位的数来进行。某种意义上讲，所有的数字计算机都是相同的，如果一台处理器从硬件上无法做到另外一台可以做到的事情，那么它可以通过软件途径做到，最终它们可以完成相同的事情，这是1937年图灵在论文里面关于可计算性的一种定义。

编码——隐匿在计算机软硬件背后的语言

274

## PDF_PHYSICAL_PAGE_INDEX=291 | PRINTED_PAGE=275

然而，速度是处理器之间的根本不同点，同时速度也是我们使用计算机的一大原因。

最大时钟频率（maximumclockspeed），也称为主频，是影响处理器速度的决定性因素之一。时钟频率决定了执行一条指令所需要的时间，处理器的数据位宽也影响处理器的速度。尽管4位处理器可以完成32位数字的加法，但速度是不能与32位处理器相媲美的。然而，令人感到迷惑的是，处理器可寻址存储器的最大空间对处理器速度也是有影响的，首先，可寻址存储器看上去只反映了处理器的某些能力，尤其是在需要大容量存储器的前提下进行数据处理的能力，而与处理器速度无关。但其实，处理器可以利用某些存储器地址去控制其他的介质来存取信息，这样就绕开了存储器容量的限制（比如，假设在特定的存储器地址写入一个字节就在一个纸带上穿一个孔，而从存储器中读出一个字节等于从纸带上读取一个孔一样)。可是这种处理办法会降低整个计算机的速度——这就又回到了速度问题！

当然，这三个数字只能粗略地反映微处理器操作的速度，它们并不能体现出微处理器的内部构造以及机器指令代码的效率和能力。随着处理器变得越来越复杂，以前通过软件完成的任务都可以在处理器上完成，我们将会在后面的章节中看到这方面的例子。

即使所有的计算机具有相同的计算能力，即使它们只能做和图灵设计的早期计算机一样简单的事情，但有一点是无法回避的，那就是处理器的速度最终决定了其用途。比如那些表现比人脑还慢的计算机是毫无用处的，跟进一步来说，如果处理器需要用一分钟来画一帧图像，那么对于现代计算机而言，要想在其屏幕上播放电影也是不可能实现的。

回到20世纪70年代中期，虽然4004有很多局限性，但毕竟只是个开始。到1972年4月，英特尔发布了8008芯片—个时钟频率为200KHz、可寻址空间为16KB的8位微处理器（瞧，用三个数字来总结一个处理器是多么简单的事）。后来在1974年5月，英特尔公司和摩托罗拉公司同时发布了8008微处理器的改进版，正是两款芯片改变了整个世界。

18 从算盘到芯片

275

## PDF_PHYSICAL_PAGE_INDEX=292 | PRINTED_PAGE=NOT_DETECTED

两种典型的微处理器

微处理器一—正是它，将计算机中央处理器的所有构成组件整合在一起，集成在一个硅芯片上—诞生于1971年。它的诞生有着很好的开端：第一个微处理器，即Intel4004系列，包括了2300个晶体管。到现在，大约三十年过去了，家用计算机的微处理器中的晶体管数量也逐步逼近10,000,000个。

从本质上说，微处理器实际上所做的工作一直没有变。在现在的芯片上，新增的几百万个晶体管所做的很多事情令我们眼前一亮，但我们正处于微处理器探索的初期，过多的关心这些当代的芯片并不合适，因为它们只会分散我们的注意力而无法帮助我们去学习与理解它。为了更清晰地认识微处理器是如何工作的，让我们首先来看一下最原始的微处理器。

我们要讨论的微处理器出现于1974年。在这一年，英特尔公司在4月推出了8080处理器，摩托罗拉公司从20世纪50年代生产半导体和晶体管—在8月推出了6800处理器。不仅如此，当年还有其他的一些微处理器面世。同年，德克萨斯仪器设备公司（Texas Instruments）推出了4位的处理器TMS1000，它用于多种计算器、玩具和设备；国家半导体公司（National Semiconductor）推出了PACE—首个16位微处理器。但当我们回顾历史的时候就会发现，8080和6800是两个最具有重大历史意义的芯片。

19

## PDF_PHYSICAL_PAGE_INDEX=293 | PRINTED_PAGE=277

英特尔为 8080 最初定的价格为 360 美元，这个价格对 IBM的 System/360 来说是极大的讽刺。System/360是大型机处理系统，用户大都是一些大公司，售价动辄几百万美元(今天，你用1.95美元就可以买到一块 8080芯片)。这并不是说 8080 可以与 System/360相提并论，但在几年之内，IBM自己也关注起这些非常小的计算机。

8080是一个8位的微处理器，它包括6000个晶体管，运行的时钟频率为2MHz，寻址空间为64KB。摩托罗拉的6800（今天的售价也是1.95美元）包括4000个晶体管，其寻址空间也是64KB。第一个版本的6800的运行速度为1MHz，但摩托罗拉于1977年推出了运行速度分别为1.5MHz和2MHz的版本。

这些芯片被称为“单芯片微处理器”（single-chipmicroprocessors)，不太准确的说法是“单芯片的计算机”。处理器只是计算机的一部分。除了处理器之外，计算机还需要其他一些设备，至少要包括一些随机访问的存储器(RAM)，一些方便用户把信息输入计算机的设备（输入设备），一些使用户能够把信息从计算机中读取出来的设备（输出设备），以及其他一些能把所有构件连接在一块的芯片。本书会在第21章详细介绍这些构件。

现在，让我们来仔细研究一下微处理器本身。当描述微处理器的时候，我们总是习惯用一些框图来阐明其内部的构件及其连接情况。然而，在第17章我们已经使用了数不清的框图来描述它，现在我们将观察微处理器和外部设备的交互过程，以此来认识其内部的结构和工作原理。换句话说，为了弄清微处理器的工作原理，我们把它视做一个不需要详细研究其内部操作的黑盒。取而代之的方法是通过观测芯片的输入、输出信号，特别是芯片的指令集来理解微处理器的工作原理。

8080和6800都是40个管脚的集成电路。这些芯片最常见的IC封装大约为2英寸长，1/2英寸宽，1/8英寸厚。

19 两种典型的微处理器

277

## PDF_PHYSICAL_PAGE_INDEX=294 | PRINTED_PAGE=278

当然，你所看到的只是外部的封装。其内部的硅晶片是非常小的，例如在早期的8位微处理器中，硅晶片还不到1/4平方英寸。外包装可以保护内部的硅晶片，并且通过管脚提供了处理器的输入和输出访问接入点。下面给出了8080的40个管脚的功能说明图。

本书中我们所创建的所有电气或电子设备都需要某种电源来供电。8080的一个特殊的地方就是它需要三种电源电压：管脚20必须接到5V的电压；管脚11需要接到-5V的电压；管脚28需接12V的电压；管脚2接地。（英特尔在1976年发布了8085芯片，目的就是简化对这些电源的要求)

其他的管脚都标有箭头。从芯片引出的箭头表明这是一个输出（output）信号，这种信号由微处理器控制，计算机的其他芯片对该信号响应。指向芯片的箭头表明该信号是一个输入（input）信号，该信号由其他芯片发出，并由8080芯片对其响应。还一些管脚既是输入又是输出。

第17章所设计的处理器需要一个振荡器来使其工作。8080需要两个不同的同步时钟输入，它们的频率都是2MHz，分别标记为 $\phi$ 和 $\phi _ { 2 }$ ，位于管脚22和15上。这些信号可以很方便地由英特尔生产的8224时钟信号发生器产生。为8224连接一个18MHz的石英晶体后，它基本上就可以完成其余工作了。

一个微处理器通常有多个用来寻址存储器的输出信号。用于寻址的输出信号的数目与微处理器的可寻址空间大小直接相关。8080有16个用于寻址的输出信号，标记为 ${ \bf A } _ { 0 } \sim$ $\mathbf { A } _ { 1 5 }$ ，因此它的可寻址空间大小为 $2 ^ { 1 6 }$ ，即65,536字节。

编码隐匿在计算机软硬件背后的语言

278

## PDF_PHYSICAL_PAGE_INDEX=295 | PRINTED_PAGE=279

8080是一个8位的微处理器，可以一次从存储器读取或向存储器写入8位数据。该芯片还包括标记为 $\mathbf { D } _ { 0 } \sim \mathbf { D } _ { 7 }$ 的8个信号，这些信号是芯片仅有的几个既可以用做输入又可以用做输出的信号。当微处理器从存储器中读取一个字节时，这些管脚的功能是输入；当微处理器向存储器写入一个字节时，其功能又变成了输出。

芯片的其余10个管脚是控制信号（control signals)。例如，RESET（复位）输入用于控制微处理器的复位。输出信号WR的功能是指明微处理器需要向 RAM中写入数据(WR信号对应于RAM阵列的写输入)。此外，当芯片读取指令时，在某些时刻一些控制信号会出现在 $\mathrm { D } _ { 0 } \sim \mathrm { D } _ { 7 }$ 管脚处。使用8080 芯片构建的计算机系统通常使用8228系统控制芯片来锁存附加的控制信号。本章在后面将会讲述一些控制信号。但8080的控制信号是极其复杂的，因此，除非你准备用该芯片搭建一台计算机，否则最好不要在这些控制信号上过多花费时间。

假设8080微处理器连接了一个64KB的存储器，这样我们就能独立地读写数据而不依赖于微处理器。

8080芯片复位后，它把锁存在存储器0000h地址处的字节读入微处理器，通过在地址信号端 ${ \bf A } _ { 0 } \sim { \bf A } _ { 1 5 }$ 输出16个0实现该过程。它读取的字节必须是8080指令，读取该字节的过程被称为取指令（instruction fetch)。

在第17章设计的计算机中，所有的指令（除了HLT指令）都是3个字节长，包括1字节的操作码和2字节的地址。在8080中，指令的长度可以是1字节、2字节，或者3字节。有些指令使8080从存储器的一个特定地址读取字节到微处理器，有些指令使8080将一个字节从微处理器写入存储器的特定地址；还有些指令使8080在其内部执行而不需要访问RAM。8080执行完第一条指令后，接着从存储器读取第二条指令，并依此类推。这些指令组合在一起构成了计算机程序，可以用来做一些很有趣的事情。

当 8080 以最高速度 2 MHz 运行时，每个时钟周期是 500ns（1 ÷ 2,000,000 =0.000000500s)。第17章中的计算机的所有指令都需要4个时钟周期，8080的每条指令需要4\~18个时钟周期，这就意味着每条指令的执行时间为 $2 \sim 9 \mu \mathrm { s }$ o

19 两种典型的微处理器

279

## PDF_PHYSICAL_PAGE_INDEX=296 | PRINTED_PAGE=280

也许了解某个特定微处理器的功能的最好办法就是全面地测试其完整的指令集。

第17章最后完成的计算机仅包括12条指令。一个8位处理器的指令数很容易达到256，每一条指令的操作码就是一个特定的8位数（如果某些指令包含2字节的操作码，其指令集会更大)。8080虽然没有这么多指令，但是其指令数也已经达到了244。这看起来似乎是很多，但从总体上说，其功能并不比第17章的计算机强大。例如，如果想利用8080进行乘法或除法运算，你仍然需要自己写一小段代码。

在第17章曾经讲到过，为了方便地引用指令，我们为处理器的每一条指令的操作码都指派了一个特殊的助记符，而且其中的一些助记符是可以带有参数的。这种助记符只是在我们使用操作码时提供方便，它对于处理器是没有帮助的，处理器只能读取字节，对于助记符组成的文本的含义一无所知（为了讲解清楚，本书选用了Intel8080说明文档中用到的部分助记符为例来说明)。

第17章设计的计算机的指令集包括两条非常重要的指令，我们称之为加载（Load）和保存（Store）。每条指令占3个字节。在Load指令中，第一个字节是操作码，其后的两个字节是要加载的操作数的16位地址。当处理器执行加载指令时，会把该指定地址中的字节加载到累加器。与之相似，当Store指令被执行时，累加器中的内容被保存到该指令指定的地址中。

我们可以用助记符把上述代码简写为以下形式：

LOD A, [aaaa]

STO [aaaa], A

这里的A表示累加器（它既是Load指令的目的操作数也是Store指令的源操作数)，aaaa表示16位的存储器地址，通常用4个16进制的数来表示一个地址。

同第17章的累加器一样，8080的8位累加器也记做A。8080也有与第17章的计算机的 Load指令和 Store 指令功能相同的两条指令，它们也称做加载(Load)和保存(Store)。在8080中，加载指令和保存指令的操作码分别是32h和3Ah，每个操作后面也同样跟着一个16位的地址。在8080中，它们的助记符分别是STA（Store Accumulator，表示加载到累加器）和LDA（Load Accumulator，表示保存到累加器）:

编码隐匿在计算机软硬件背后的语言

280

## PDF_PHYSICAL_PAGE_INDEX=297 | PRINTED_PAGE=281

8080芯片的微处理器的内部除累加器外还设置了6个寄存器(register)，每个寄存器可以存放一个8位的数。这些寄存器和累加器非常相似，事实上累加器被视为一种特殊的寄存器。这6个寄存器和累加器一样，本质上都是锁存器。处理器既可以把数据从存储器读入寄存器，也可以把数据从寄存器存回存储器。当然，其他的寄存器没有累加器所具有的丰富的功能，例如，当把两个8位数相加时，其结果总是保存到累加器而不会保存到其他寄存器。

在8080中用B，C，D，E，H和L来表示新增的6个寄存器。人们通常会问以下两个问题：“为什么不使用F和G来表示？”，以及“I，J和K用来代表什么？”答案是，使用H和L来命名寄存器是因为它们具有特殊的含义，H可以代表高（High）而L可以代表低(Low)。通常把两个8 位的寄存器H和L 合起来构成一个16 位的寄存器对(registerpair)，称做HL，H用来保存高字节而L用来保存低字节。这个16位的值通常用来对存储器寻址，我们将在下面看到它是怎样以简单的方式工作的。

寄存器是计算机必不可少的部件吗？为什么在第17章搭建的计算机中并没有寄存器的踪迹？从理论上讲，这些寄存器不是必需的，在第17章也没有用到它们，但在实际应用中使用它们将带来很大的方便。很多计算机程序都同时用到多个数据，将这些数据存放在寄存器比存放在存储器更便于访问，因为程序访问内存的次数越少其执行速度就越快。

在8080中有一条指令至少用到了63个操作码，这条指令就是MOV，即Move的缩写。其实该指令是一条单字节指令，它主要用来把一个寄存器中的内容转移到另一个寄存器（也可能就是原来的寄存器）。因为8080微处理器设计了7个寄存器（包括累加器在内)，因此应用中使用大量的MOV指令是很正常的。

下面列出了前32条MOV指令。再一次提醒你，两个参数中左侧的是目标操作数，右侧的是源操作数。

19 两种典型的微处理器

281

## PDF_PHYSICAL_PAGE_INDEX=298 | PRINTED_PAGE=282

这些指令使用起来非常方便。利用上面的指令可以方便地把一个寄存器存放的数据转移到另一个寄存器。下面让我们研究一下以HL寄存器对作为操作数的4条指令。

MOV B, [HL]

前面讲过LDA指令，它可以把单字节的操作数从存储器转移到累加器；LDA操作码后面直接跟着该操作数的16位地址。在上面列出的指令中，MOV指令把字节从存储器转移到B寄存器，但该字节的16位地址却存放在HL寄存器对中。HL是怎样得到16位存储器地址的呢？这并不难解决，有很多方法可以做到，比如通过某种计算实现。

总而言之，对于下面这两条指令：

LDA A, [aaaa]

MOV B, [HL]

它们的功能都是把一个字节从内存读入微处理器，但它们寻址存储器的方式并不相同。第一种方式称做直接寻址（direct addressing）；第二种方式称做间接寻址（indexedaddressing)。

下面列出了其余32条MOV指令，我们看到HL保存的16位存储器地址也可以作为

编码隐匿在计算机软硬件背后的语言

282

## PDF_PHYSICAL_PAGE_INDEX=299 | PRINTED_PAGE=283

日标操作数。

其中的一些指令如：

MOV A, A

并不会执行有意义的操作。而指令：

MOV [HL], [HL]

是不存在的，事实上，与之对应的指令是HLT（Halt）即停止指令，也就是说该指令的意义是停止。

研究MOV操作码的位模式能更好地了解它，MOV操作码由8位组成：

01dddsss

其中ddd这3位是目标操作数的代码，sss这3位是源操作数的代码。它们所表示的意义如下：

19两种典型的微处理器

283

下一段：[继续读取](https://workshop.closeclaw.top/api/ai/read/38270854-596f-4a26-8183-db8c968c6020.md?start=300&limit=10)
