《编码》读书笔记:从无到有构建计算机系统
1 简单的电报系统:
按键、发声装置,电池和一些导线即可构成:
当电报机的键按下时,发生器的电磁铁将可动棒拖下发出“滴”的声音;当键放开时,棒弹回初始位置,发出“嗒”的声音。快速的“嘀嗒”为点,慢速的则为划。
2 继电器
电磁式继电器一般由铁芯、线圈、衔铁、触点簧片等组成的。只要在线圈两端加上一定的电压,线圈中就会流过一定的电流,从而产生电磁效应,衔铁就会在电磁力吸引的作用下克服返回弹簧的拉力吸向铁芯,从而带动衔铁的动触点与静触点(常开触点)吸合。当线圈断电后,电磁的吸力也随之消失,衔铁就会在弹簧的反作用力返回原来的位置,使动触点与原来的静触点(常闭触点)吸合。这样吸合、释放,从而达到了在电路中的导通、切断的目的。对于继电器的“常开、常闭”触点,可以这样来区分:继电器线圈未通电时处于断开状态的静触点,称为“常开触点”;处于接通状态的静触点称为“常闭触点”。
长距离导线会有很大的电阻,会导致电流越来越小。下图中的继电器系统就是为了增大电流。
上述通信系统中的继电器的简单实现:
3 逻辑代数与电路
逻辑代数是分析和设计逻辑电路的数学基础。逻辑代数是由英国科学家乔治·布尔(George·Boole)创立的,故又称布尔代数。
4 逻辑门 (logic gates)
逻辑门和通常让水和人通过的门十分相似。逻辑门通过阻挡或允许电流通过在逻辑中执行简单的任务。
(1)与门
用两个继电器串联成一个与门
(2)或门
用两个继电器并联成一个或门
标准表示:
(3)反向器
标准表示:
它被称为反向器的原因是当输入为0时输出却为1,反之亦然。
(4)或非门
标准表示:
(5)与非门
标准表示:
(6)缓冲器
缓冲器的特点是“什么都不做”,其输出和输入是相同的:当输入信号很弱时,可以使用缓冲器,这是因为这也正是多年前继电器被用于电报当中输入输出的原因。此外,缓冲器也可用于延迟一个信号,这是因为继电器可能要求多一点儿动作时间,如1秒的几分之一才被触发。
标准表示:
5 加法器
二进制的加法表:
+ | 0 | 1 |
0 | 00 | 01 |
1 | 01 | 10 |
这样一来,二进制数字相加的结果是两位数,分别称为“和”和“进位”(比如“ 1加1等于0,进位是1”)。现在,可以把这张二进制加法表分成两张表,第1张是表示“和”的表。下面表(1)是加法位的:
+加法位 | 0 | 1 |
0 | 0 | 1 |
1 | 1 | 0 |
下面表(2)是进位的:
+进位位 | 0 | 1 |
0 | 0 | 0 |
1 | 0 | 1 |
这样的话就便于用之前的逻辑门电路来分别实现上述两张表的功能。
表(2)很简单,可以用与门实现;表(1)略复杂,如下:
进而可以构成半加器 → 全加器 → 8位加法器 → ...
8位加法器如下:
层层组合:继电器 → 逻辑门 → 加法器
当然现代计算机已经不使用继电器了,后来使用过真空管,现在使用的是晶体管,但是工作方式和继电器是基本相同的。继电器 → 真空管 → 晶体管。
6 减法器
减法器主要通过一些变换,最后转换为加法器来处理。
一个减法器的组成:
7 锁存器
将继电器、电池、开关按如下形式连接:
只要开关是闭合的,金属簧片就会上下跳动—使电路闭合或断开—并制造一种声音。
对于反向器而言,当输入为0时,输出为1;输入为1时,输出为0。在该电路中闭合开关会使反向器中的继电器间断地闭合和断开。如果去掉开关,可以使反向器连续地工作,如下图示:
这个电路称为振荡器,它和我们以前见到的每样东西都有本质上的区别。以前,所有的电路都靠手动地断开或闭合开关来改变状态,而振荡器却不需要人的干涉,它可以自主地工作。
所有计算机都靠某种振荡器来使其他部件同步工作。振荡器的输出是0和1的交替序列,可以用下图形象地来表示它,图中,水平轴表示时间,垂直轴表示输出是0或1:
此图表示随着时间的变化,振荡器的输出在0和1之间交替变化。基于这个原因,振荡器有时称为时钟(c l o c k),因为通过对振荡次数记数还可确定时间。我们把振荡器从某个时间的输出开始,经历一段变化又回到同样输出的这一段间隔称为振荡器的一个循环(c y c l e),一个循环所需要的时间称为振荡器的周期。
如下电路是一个基本的触发器电路:
触发器电路可以保持信息,换句话说,它有记忆性。它可以“记住”最近一次是哪个开关先闭合的。
可以进一步构成锁存器。锁存器不同于触发器,它不在锁存数据时,输出端的信号随输入信号变化,就像信号通过一个缓冲器一样;一旦锁存信号起锁存作用,则数据被锁住,输入信号不起作用。锁存器也称为透明锁存器,指的是不锁存时输出对于输入是透明的。
8 存储器
8个1位锁存器,3-8译码器,8-1选择器构成的一个8×1RAM,如下图所示:
这种锁存器的配置有时也称为读/写存储器,但通常叫作随机访问存储器或R A M。称它为存储器是因为它能保存信息,称为读/写存储器是因为可以在每个锁存器中保存新的数据(也就是写数据),同时还可以查看每个锁存器中所保存的数据(也就是读数据)。称它为随机访问存储器是因为通过简单地改变地址输入就可以从8个锁存器中的任意一个读出或写入数据。相比之下,其他类型的存储器必须顺序读出—也就是,在可以读出存储在地址1 0 1的数据之前,必须读出存储在地址1 0 0的数据。
可以将多个8×1RAM构成一个整体的RAM,两种组合思路:增加数据宽度(数据线),增加地址线宽度。
为什么RAM具有易失性?
如果一个装满65 536字节的6 4 K×8 RAM阵列被关掉电源,将会发生什么情况呢?所有的电磁铁将失去磁性,所有继电器的触点将回到未触发状态, R A M中的内容也将永远丢失。
这就是随机访问存储器也称为易失性存储器的原因,它需要恒定的电源来保持其中的内容。
9 计算机雏形
用来累加多个数的锁存器成为累加器(accumulator)。
(1)version 1.0
(2)version 2.0
(1)初步产生两个,一个是数据RAM,一个是代码RAM。代码RAM阵列中存放的每一个代码都对应着数据RAM中要被加载或者加到累加器中的数,或者对应需要存回到数据RAM中的某个数。以这种方式使用的数字代码常常被称为指令码(instruction code)或操作码(operationcode)。代码存储器中的每一条指令对应数据存储器中相同地址的存储单元。
(2)支持save、sub指令功能。
(3)version 3.0
1)带参数的指令。改成一个指令占3个字节。第一个为代码本身,后两个为16位存储器单元地址。是为了解决之前 版本的问题,具体问题分析见 P203
2)合并数据RAM和代码RAM。
从存储器中取出指令的过程称为取指令(instruction fetch)。在上述加法机中,每个指令长3个字节。因每次只能从存储器中取出一个字节,因此每次取指令需要3个时钟周期。
机器响应指令代码执行一系列操作称为执行(execute)指令,但这并不是说机器是有生命的东西,因为它不能自行分析机器代码并决定该做什么。每一个机器码用其唯一的方式触发多种控制信号,使机器产生各种操作。
能否控制重复操作或者循环是计算机和计算器的区别。
我们的计算机是用继电器、电线、开关和灯泡建造的,所有这些都是硬件。与之对应,指令和输入存储器中的其他数据叫作软件,之所以叫“软件”是因为它们比硬件更容易改变。
上述图中:
CPU包含若干组件:累加器(由8位锁存器构成)是其中一个。
8位反相器和8位加法器构成了ALU(本例中只能进行算术运算)。
16位的计数器被称为程序计数器(PC,Program Counter)。
处理器可以响应的操作码(如指装载和存储的1 0 h和11 h)叫作机器码,或机器语言。之所以用“语言”这个术语是因为机器码类似于可读/写的人类语言可被机器理解和响应。
以上表示的是一种计算机程序设计语言,称作汇编语言。它是全数字的机器代码和指令描述性语言的综合,且存储器地址用符号表示。人们有时会把机器语言和汇编语言弄混淆,因为它们是表示同种事情的两种不同的方法。汇编语言的每条语句都对应于机器代码的特定字节。
10 冯诺依曼体系结构
早期的计算机中存储器只是用来存储中间结果,程序本身则存储到一些物理媒介上面,例如带穿孔的纸带。并且使用的还不是二进制数字系统(ENIAC用的是十进制)。
冯诺依曼提出:计算机内部应该使用二进制数;计算机中应该拥有尽可能大容量的存储器,这些存储器应该用来存储程序代码和程序执行中产生的数据;这些指令在存储器中是顺序存放的,而且可以由程序计数器进行寻址,但允许条件跳转。这就是存储程序概念(stored-program concept)。
11 计算机的发展
芯片:指内含集成电路的硅片,体积很小,常常是计算机或其他电子设备的一部分。集成电路实体往往要以芯片的形式存在。
某种意义上,所有数字计算机都是相同的。如果一个处理器的硬件能做别的处理器做不了的,那么别的处理器可以用软件实现,最终它们能做同样的事情。
以下三个指标经常用来作为微处理器相互比较的标准:
- 处理器的数据通路的宽度。
- 时钟频率是可连接到微处理器并能运行的振荡器的最大频率。时钟频率决定了每一条指令的执行速度。
- 可寻址空间大小。
12 8080微处理器
(1)除了累加器,8080微处理器内部还包括6个寄存器(register),每个寄存器可以保存8位的值。这些寄存器和累加器非常相似,事实上,累加器被看作是一种特殊的寄存器。和累加器一样,这6个寄存器也是锁存器。处理器可以把数据从存储器传送到寄存器,也可以把数据从寄存器送回到存储器。然而,这些寄存器没有累加器的功能强大。
(2)该是谈论8080标志位的时候了。在第17章的处理器中,已有进位标志位C F和零标志位ZF。8080还有3个标志位,即符号标志位S F、奇偶标志位P F和辅助进位标志位A F。所有标志位都保存在另一个叫作程序状态字(PSW:program status word)的8位寄存器中。
(3)堆栈是怎样实现的呢?首先,堆栈只是不被别的东西使用的正常的RAM的一部分。8080微处理器包含一个特殊的16位寄存器来对这一部分存储器进行寻址,这个16位寄存器叫作堆栈指针。
(4)对每个PUSH指令,堆栈都会增加2个字节,这可能导致程序出现小毛病—堆栈可能会变得很大以致会覆盖掉程序所需的一些代码和数据。这就是堆栈上溢问题。同样,过多的POP指令会过早用光堆栈内容,这就是堆栈下溢问题。由于程序代码放在低地址空间,为了避免相互干扰,一般sp指向的是高地址空间,然后堆栈向低地址空间增长。
(5)第一个是Call(调用)指令。Call指令与Jump指令的不同之处在于:前者把一个新值装入到程序计数器PC中,处理器保存PC中原来的地址,保存在哪里?当然,在堆栈中。这种策略意味着Call指令可有效地保存“程序从哪里跳转”的标记。处理器最终可利用此地址返回到原来的位置。这个返回指令叫Return。Return指令从堆栈中弹出两个字节,并把该值装载到PC中。
(6)微处理器是怎样与外围设备(对于连接到微处理器而不是存储器的东西的称呼)进行通信的呢?外围设备具有与存储器相似的接口,微处理器可通过对应于外设的具体地址来对外设进行读写。在有些微处理器中,外围设备实际上占用了通常用来寻址存储器的地址,这种配置叫作内存映像I/O。然而在8 0 8 0中,在65536个正常地址外还有256个附加地址专门为输入输出设备预留,这些就是I/O端口(I/O Port)。I/O地址信号为A0~A7,但I/O访问与存储器访问不同,由8228系统控制芯片锁存的信号来区分。
13 ASCII码和字符转换
数字计算机中唯一可以存储的是比特。
人类所积累的大部分信息,都是以各种文本形式保存的,这些文本信息是由各种人类可识别的符号(字符)构成的,比如字母、数字,标点符号等等。
为了将文本信息存储在计算机中,需要对每一个字符赋予一个唯一的编码(比特序列)。
所谓编码表就是指 “字符 → 编码(计算机中就是二进制比特序列)” 的这样映射表。
这样每一个字符的编码就会占据一定的比特。
对数字编码?
数字(0-9)也是一种字符,所以可以像其他字符一样,为每个字符赋予一个唯一的编码。问题不就解决了。就看成普通字符就完事了嘛。
问题是数字在计算机中可以用十六进制码、BCD码等形式来表示,所以很蛋疼。
比如十进制数:12
ASCII码:00110001 00110010 ;即31h和32h。
BCD码:00010010 ;用4位二进制数来表示1位十进制数中的0~9这10个数码。
十六进制码:00000001 00000010 ;即01和02h。
当数字以文本流的身份出现时,是以ASCII编码的。和该数本身表示的含义无关。也就是说我们平时从键盘输入一个数字(0-9)都是ASCII码形式的。
14 I/O设备
输出设备:比如视频显示器CRT(电子射线管)。
视频适配器是独立存在的,它们拥有自己的电路板,也就是我们常说的显卡。视频适配器为视频显示器提供信号。
视频适配器中必须配置有一些RAM,用以存储显示的内容;微处理器也必须能够向此RAM中写入数据以改变显示器上显示的内容。当然这个RAM也可以是微处理器存储空间的一部分。
字符生成器也是视频适配器板上的一部分,包含了所有ASCII码字符的像素图,它是只读存储器,即ROM,这些数据在厂家制造芯片时已经配置好了,当然你也可以对ROM芯片进行编程。可编程只读存储器PROM只能编程一次,而可擦除只读存储器EPROM可以重复擦除和写入。
只显示文本的视频显示适配器还必须支持光标功能。光标所在的行和列常被存储在两个8位的寄存器中,这两个寄存器也是视频板的一部分,而且微处理器可以对其进行写操作。
从键盘输入字符,然后显示在显示器上的过程?
按下键盘中的某个键,产生一个对应的扫描码,(注意,一般的键盘是不会本身提供ASCII码对按键的对应关系的),然后通过一小段计算程序计算出这个按键对应的ASCII码。
按下某个按键→产生中断→运行中断处理程序(在这个程序中会计算出这个按键对应的ASCII码,并写入存储器中)。
按照代码转换方式键盘可以分为编码式和非编码式两种。编码式键盘是通过数字电路直接产生对应于按键的ASCII码,这种方式目前很少使用。非编码式键盘将按键排列成矩阵的形式,由硬件或软件随时对矩阵扫描,一旦某一键被按下,该键的行列信息即被转换为位置码并送入主机,再由键盘驱动程序查表,从而得到按键的ASCII码,最后送入内存中的键盘缓冲区供主机分析执行。
具体可参看这里。
一般我们从键盘输入的最后都会以ASCII的方式存放到存储器,这些ASCII字符可以输出给显示适配器,然后显示器显示这些ASCII字符。
虽然这些ASCII字符是存储在内存中的,但它们不是可执行的文件,因为这些字节编码代表字符,而不代表指令。
假设我们的命令行处理程序可以处理如下命令:
MOV A 3A
假设该命令会将十六进制表示的3A送到累加器A中,则键盘程序处理后的3A就变成了如下两个ASCII编码 33h 41h,而我们期待A中存放的是3Ah,那么中间肯定会存在一个转换程序:将 33h 41h 转为 3Ah。