Kaito's Blog

致力成为一枚silver bullet.

0%

《编码:隐匿在计算机软硬件背后的语言》读书笔记11-17

11、门

通过串联或并联的开关组成继电器完成简单的逻辑任务,继电器的组合叫做逻辑门,逻辑门一般有两个或多个输入

继电器的优点是:可以被其他继电器控制,而不需要人工控制,意味着简单的逻辑门组合起来可以完成复杂的功能。

如何连接继电器,是逻辑门的关键:

  • 继电器串联:与门(AND)
  • 继电器并联:或门(OR)
  • 反向器:NOT
  • 只有1-1输出0:或与门(NAND)
  • 只有0-0输出1:或非门(NOR)
  • 延迟信号:缓冲器

利用4个门与2个反向器连接的电路叫做2-4译码器:2个输入,输出4种不同的信号。

同样的原理可以制造出3-8译码器或4-16译码器。

由缓冲器、反向器、四种基本逻辑门可以组成复杂电路。

12、二进制加法器

一对二进制数相加的结果,有2个数位:加法位、进位位,这2个数位计算是分别进行的。

  • 进位位逻辑:与门
  • 加法位逻辑:或门 + 与非门 = 异或门(XOR)

2个输入 –> 异或门 –> 结果 –> 与门 = 半加器

2个半加器 + 或门 = 全加器

  • 组成与门、或门、与非门(3 * 2 = 6个继电器)
  • 异或门 + 与门 = 半加器(8个继电器)
  • 2个半加器 + 或门 = 全加器(18个继电器)
  • 8个全加器= 8位二进制加法器(144个继电器)

全加器的计算原理就是计算机的加法原理,但这种进位方式叫行波进位(脉冲进位),更快的加法器使用前置进位提高运算速度。

现如今的计算机使用晶体管,耗能低、价格低、体积小,但如果搭建一个8位加法器依然需要144个晶体管,如果使用前置进位法,将用到更多的晶体管,但电路是体积非常小。

13、如何实现减法

十进制减法计算步骤:

  • 减数大于被减数:被减数 - 减数 = 减数位个9 - 减数 + 被减数 + 1 - 10^减数位数
  • 减数小于被减数:被减数 - 减数 = -(减数位个9 - (减数位个9 - 减数 + 被减数))

二进制减法计算步骤:

  • 减数大于被减数:被减数 - 减数 = 减数位个1 - 减数 + 被减数 + 1 - 2^减数位数
  • 减数小于被减数:被减数 - 减数 = -(减数位个1 - (减数位个1 - 减数 + 被减数))

8个异或门连接为求补器1个求补器+1个8位加法器+1个异或门形成可完成加法和减法的电路。

用2的补码来表示二进制中的负数,最高位代表符号位。

14、反馈与触发器

2开关+电池+磁铁可以完成一个循环电路,如果连上金属簧片可以形成一个蜂鸣器,也可以叫振荡器

振荡器可以在不需要人干涉的情况下,自发工作。

振荡器在0和1之间交替规律变化,又称为时钟

振荡器从某个初始状态开始,经过一段时间又回到初始状态的间隔,称为周期

周期的倒数就是振荡器的频率,也叫赫兹

2个或非门+2个开关+1个灯泡的电路,左边或非门的输出是右边或非门的输入,而右边或非门的输出是左边或非门的输入,这种连接方式称之为反馈

而当2个开关都断开时,电路有2个稳定态,这类电路统称为触发器触发器可以“记住”某些信息,这类电路叫做R-S(复位/置位)触发器,这类触发器的特点在于:可以记住哪个输入端最终状态为1

现在把2个输入分别叫做数据端和保持位,经过分析,保持位为0意味着输出不被数据端所影响,那么电路演变可以为:增加2个与门,变成3个输入:复位、保持位、置位,此时的电路和之前电路功能是相同的。

但是我们只想要2个输入,继续分析电路后得出:2个输入端同时为0是无意义的,而同时为1是非法的,因此只要将保持位设置为0,即可完成相同功能,电路演变为:复位和置位变为1个数据端+反向器代替,这样就有2个输入了:保持位+数据端。

此时的电路称为电平触发的D型触发器,即当保持位输入为某一特定电平,触发器保存数据端的输入。

通常情况下,保持位又叫做时钟,它可以在0和1之间规律来回变化,但此时的时钟仅用来指示什么时候保存数据。

至此,此电路就是电平触发的D型锁存器,也叫1位存储器,它可以锁存住1位数据并保持它,以便将来使用。

由2级R-S触发器连接的电路,时钟端既控制第一级R-S触发器,也控制着第二级,只有当时钟信号由0变为1时,数据端的输入才被保存下来,输出0到1或1到0,而下级触发器的频率正好是上级触发器频率的一半,这种电路叫分频器,就这样多个振荡器连接下去,就形成了计数器

至此,我们可以通过使用继电器形成的电路来加法、减法和计数了。

15、字节与十六进制

8位代表1个字节(byte),追溯历史原因,8位可以表示0-255共256种不同的事物,而最早的书面语言的基本字符都少于256个,所以使用8位表示1个字节是比较理想的手段,通用1个字节也可以表示RGB256种颜色值。

如果要表达的事物1个字节不够用,则可以扩展字节,采用2个字节甚至更多字节来表示,表示起来也很方便(扩展方便)。

把1个字节分为每4位为1组,进而演化出16进制,1个16进制位表示4位,表达起来也很方便。

16、存储器组织

把之前的D型电平触发器的时钟端、数据端分别改名为写操作端,数据输入,然后把多个这种1位锁存器连接起来,就形成了多位锁存器

目前的电路,只能存储1个8位二进制数,如果想存储8个单独的比特怎么办?

使用8-1数据选择器,来控制哪个比特位存储。

目前输出端可以满足要求,控制每个比特位的单独存储。

但输入端包括了数据输入和写操作信号,要想合并这2个,只要一个输入端,使用3-8译码器即可完成合并。

译码器和选择器具有相同的选择信号,放在一起叫做地址端口

通过3-8译码器的输入端,地址决定哪个锁存器可以被写操作端信号触发来保存数据,在输出端,8-1选择器来通过地址选择8个锁存器中的1个,最后输出。

至此,完成了一个可以存储8个单独比特的随机存储器(RAM)

将多个RAM组织起来可以形成RAM阵列

RAM阵列的存储容量与地址输入端的数量有直接联系,RAM阵列的存储容量=2^地址输入端的个数。

同理,使用RAM阵列就可以组织处10248的RAM,即1KB的RAM,其有*8个数据输入端、8个数据输出端和10个地址输入端(2^10=1024)**,地址输入端决定RAM的存储能力。

继续就能组织出64K*8的RAM,此RAM需要16个地址输入端,地址范围为0000h~FFFFh。

但是产生的另一个问题就是,组装出此电路的电路零件非常多,很难管理,如果使用一个控制面板来管理,就会简单的多。

控制面板上有16个开关用于控制地址位,8个开关控制输入的8比特数据,写操作端用1个开关,8个灯泡显示8位数据,最后还有个控制开关,控制是否来自其他电路的控制(其实就是CPU来控制)。

至此,我们制造出了64KB8的RAM,能存储65536个8位数,并且此电路可以*接入其他电路,使其他电路来读、写存储器。**

但是由于此RAM都是通过逻辑门和电路磁片组成的,所以断电后,将失去存储能力,这就是RAM断电后丢失数据的特点。

17、自动操作

现在如果想计算多个数相加的结果,用1个8位加法器+1个8位锁存器就可以完成,但是有2个缺陷:

  • 无法计算结果大于255的数
  • 如果加数很多,输入的过程中一旦输入错误,则需重新输入

由于以上缺陷,可以连接之前的64k*8的RAM阵列,RAM的输入是一个16位数计数器(由之前的触发器组成),RAM的输出连接加法器的输入,这样就可以把输入的数先保存到RAM中,每次输入都会通过计数器在RAM中寻址后保存,这样等全部输入完成后,就可以等待加法器依次相加得出结果。

这种电路只能上述说的第2个缺陷,但第1个缺陷还是无法解决,并且此电路启动后,无法停止。

上面所述的加法是,依次输入后,其先保存到RAM中,再输出给加法器,依次相加。

如果想计算50对数相加,产生50个结果,然后保存到RAM中,并且可以任意读取这50个结果,怎么做?

改造电路,使8位锁存器的输出连接到RAM的输入端,也就是说把计算后的值,再写回到RAM中保存,就可以达到目的。

目前解决问题需要如何配置一个自动加法器,不仅可以对一组数字做累加运算,还能自主确定累加了多少数字,并且能记住在RAM中存放了多少个计算结果?

经过分析,我们希望8位锁存器能做4件事:

  • 把一个字节从RAM中加载到累加器(Load)
  • 把RAM中的一个字节加到累加器中(Add)
  • 把累加器的计算结果存放到RAM中(Store)
  • 可以自动停止(Halt)

解决上述问题,需要引入另一个RAM,这个RAM来保存这些Load、Add、Store、Halt操作码,也就是说电路中有2个RAM共同工作,RAM1保存了数据,RAM2保存了代码(指令)。同时,要想达到8位锁存器Load指令的效果,需改造电路,8位加法器的输出与一个2-1选择器连接,2-1选择器连接RAM2和8位锁存器,这样锁存器就可以实现从RAM2中执行Load指令。

如果要实现减法如何做?有了之前由加法可以变相计算减法的逻辑,可以在RAM2和加法器之间连接一个反向器,就可以实现减法操作

回到最开始提的问题,如何解决结果不能大于255的问题?解决办法是,把加数拆分,分别计算高字节和低字节的和,然后合并就可以得到结果。

这里又产生一个问题,如果低字节加法计算后,需要进位,这个进位需要与高字节累加才是正确结果,解决方法是:引入1个1位锁存器,叫它进位锁存器,同时引入一个“进位加法”的指令,专门保存进位的值,然后再和高字节累加计算。

同理,减法如何需要借位,添加一个“借位减法”的指令,此指令将减数取反,并把加法器的进位输入变为1。

截止现在,此电路不限于计算8位数的加法运算,也可以计算16、24、32及以上位数的运算,包括加法和减法。

但现在的电路有个问题,如果几个数相加,得到了结果,但是想再减去一个数,却做不到,不能复用之前的结果。

产生此问题的原因在于代码存储器和数据存储器是同步的、顺序的,代码存储器每一条指令对应数据存储器相同地址的存储单元。

解决此问题的方案是:每一个指令占据3个字节,第1个字节代表操作码,后2个字节存放1个16位存储器单元地址。

改造电路,把指令RAM阵列输出改为3个8位锁存器,第1个锁存器保存指令代码,后2个锁存器保存16位地址,输出给数据RAM阵列。

现在使用了3个字节存储指令和数据,那么就可以把2个RAM合为1个RAM。改造电路,去掉数据RAM,把2个8位锁存器的输出接入到2-1选择器然后连接RAM。

现在的电路虽然可以完成基本功能,但是还不够完美,因为现在的电路使用地址空间是要非常小心的,如果不注意,就会发生地址被覆盖的情况,导致执行错误。

要解决此问题的方法是:加入一个跳转(jump)指令,同时改造电路,使指令的后2个字节输出也可以输出到计数器,然后通过计数器来确定遇到跳转指令后,计数器输出需跳转的地址,完成跳转寻址。

如何完成2各数相乘的运算?那么就可以使用跳转指令完成,但是还是不够,这里需要一个跳转条件来配合,达到什么条件后才发生跳转。

增加1个锁存器,叫做零锁存器,只有当加法器的输出全部为0时它的值才是1。通过计数器和零锁存器的配合,就可以计算乘法运算。

当然同理,实现除法、平方根、取对数、三角函数运算也都是可行的。

到这里,我们完成了一个计算机的核心功能,包括:处理器、存储器、输入设备、输出设备。这里的处理器即是CPU,主要负责控制和逻辑运算。

处理器包括若干组件,累加器就是其中一个非常重要的组件,它是一个锁存器,用来保存处理器内部的部分数据。

在此电路设计中:

  • 8位反向器和8位加法器构成了算数逻辑单元(ALU),其只能进行算数运算(主要是加法和减法,在以后的计算机中可以进行逻辑运算)
  • 16位计数器叫做程序计数器(PC),其实就控制单元

我们设计的计算机由继电器、电线、开关、灯泡构成,这些都叫硬件,而存储器中的指令和数值叫做软件,平时我们所说的“编写代码”就是做软件的工作。

计算机处理的操作码(如Load、Add、Store)最终转换数字的其实叫做机器码或机器语言,这些操作码也叫做助记符,方便“编写”,但其本质还是转换为机器码。

用操作码和地址表示的程序,叫做汇编,它是机器语言和指令的文字描述的结合体,使用汇编语言的好处在于降低了使用机器代码编写的错误率,同时易于理解。

如果此文章能给您带来小小的工作效率提升,不妨小额赞助我一下,以鼓励我写出更好的文章!