1. 冯.诺依曼结构
1.1 存储程序概念
数字计算机最独特的特点在于其功能多样性,一个由有限硬件组件构成的计算机却可以执行无限的任务队列;
计算机基于固定的硬件平台,能够执行固定的指令集,同时这些指令能被当成构建模块组成任意的程序;不同于1930年以前的机械计算机,这些程序的逻辑并没有被嵌入到硬件中,而是被存储到计算机的存储设备(memory)里,和数据一样,成为所谓的软件,由此,同样的硬件平台可以实现完全不同的功能
1.2 冯.诺依曼结构
冯诺依曼机是实际应用型的体系结构,他几乎是今天所有计算机平台的基础;其体系结构的核心是存储程序的概念:计算机内存不仅存储着要进行操作的数据,还存储着指示计算机运行的指令;
冯诺依曼体系结构的基础是一个中央处理单元(cpu),他与记忆设备(memory内存)进行交互,负责从输入设备接受数据,向输出设备发送数据;
① 内存
冯诺依曼机的内存中存有两种类型的信息:
- 数据项
- 程序指令
在某些计算机中他们被存储到不同的内存区中
数据内存
: 高级程序操纵抽象的原件,例如变量,数组,对象;这些数据抽象被翻译为机器语言后,变成一连串的二进制数,存储在计算机的数据内存中;一旦通过指定的地址,在数据内存中找到对应的内存单元,就可以对该内存单元进行读操作或写操作;指令内存
: 当高级命令被翻译成机器语言时,它变成一系列的二进制字,这些字代表机器的指令;这些指令被存储在计算机的指令内存中;在计算机操作的每一步,CPU从指令中取出一个字,对其进行解码,从而执行指定的指令,然后计算下一条将要执行的指令;
② 中央处理器
CPU是计算机体系的核心,负责执行已经被加载到内存中的指令;这些指令告诉CPU区执行不同的计算,对内存进行读写操作,以及根据条件去跳转去执行程序中其他指令;
CPU通过使用三个主要的硬件要素来执行任务:
算术逻辑单元ALU
:ALU负责执行计算机中所有底层的算数操作和逻辑操作;比如相加,位运算等寄存器Registers
:CPU的设计是为了快速地执行简单计算;为了提高它的性能,将这些和运算相关的数据暂时存储到某个局部存储器中是十分重要的,这远比从内存搬入搬出要好,因此每个CPU都配有一组高速寄存器,每个寄存器能保存一个单独的字控制单元Cntrol Unit
:计算机指令用二进制代码来表示,在指令能够被执行之前,需对其进行解码,指令里面包含的信息向不同的硬件设备(ALU,存器,内存)发送信号,指示他们如何执行指令;指令的解码过程是通过某些控制单元完成的,这些控制单元还负责决定下一步需要取出和执行哪一条指令
CPU操作可以被描述成一个重复的循环:从内存中取出一条指令,将其解码;执行该指令;取下一条指令;如此反复循环;
指令的执行过程中可能包含一些子任务:让ALU计算值,控制内部寄存器从存储设备中读取一个字,或向存储设备中写入一个字,在这些认为的过程中,CPU也会计算出下一步该读取并执行哪一条指令
③ 寄存器
内存的访问是很慢的,寄存器也能提供和内存同样的数据访问功能,但没有来回数据传递和寻址的开销
- 寄存器位于CPU内布
- 与数百万个内存单元相比,寄存器的数量非常少,因此,机器语言指令可以使用短短几个位指定要操作的寄存器在什么位置,这样的指令格式也更短
基于不同的目的,不同的COU采用不同数量,不同类型的寄存器
数据寄存器
:这些寄存器为CPU提供短期记忆服务,比如当计算(a-b)*c
时必须先计算(a-b)
的值并记住他,虽然这个结果可以暂时存在内存中,但是更好的办法是存储在CPU内部的数据寄存器中寻址寄存器
:为了进行读写,CPU必须连续访问内存中的数据,这样我们必须确定被访问的内存字所在的内存地址,在某种情况下这个地址作为当前指令的一部分给出,二而其他情况下它依赖于前面一条指令的执行结果;对于后者,这个地址应该被存储到某个寄存器中,使得该寄存器的内容在今后的操作中能被当作存储单元的地址,这就需要用到寻址寄存器程序计数寄存器
:执行程序时,CPU必须总是知道下一条指令在指令内存中的地址,这个地址保存在一个特殊的寄存器即程序计数器中
④ 输入和输出
计算机使用一组输入输出设备(屏幕,键盘,光驱等)来与其外部环境进行交互;计算机科学家设计不同的方案将不同外设的物理细节封装起来,让计算机能以相同的方式对它们进行操作,其中最简单的实现技巧是IO映像
IO映像的基本思想是:创造IO设备的二进制仿真,使其对于CPU而言看上去就像普通的内存段;特别的,每个IO设备在内存中都分配了独立的区域,作为它的内存映像
- 对于输入设备,内存映像能连续不断的反映设备的物理状态,当外部事件作用于输入设备时,比如键盘输入,某个特定的值就被写入到他们各自对应的把内存映像中
- 对于输出设备,内存映像连续地驱动设备的物理状态,想要控制某些输出设备,比如在屏幕上显示图像,就将一些特定值写入他们各自对应的内存映像
2. 基本构件
① CPU
输入:
- 数据值:CPU要运行的值
- 指令
- 重置
输出:
- outM:输出值
- writeM:是否写入内存存储
- addressM:要写入的内存地址
- pc:下一条指令的地址
从输入a指令开始
- 首先输入的指令会被解码为一个操作为和15位的数据值
- 数据值会被存储到寄存器A中
输入c指令
首先解码,c指令包含4个部分
- Op-code
- ALU control bits
- Destination load bits
- Jump bits
可以看到Mux16根据输入的是a指令还是c指令决定存入A寄存器的是来自指令的值还是从ALU输出的值(control bit c)
对于ALU来说由x,y以及6个控制位的输入,下图中可以看到,两个输入分别来自
- D寄存器
- A寄存器/M寄存器
6个控制位则是从操作指令中获得的
ALU的计算结果可能会被输出到3个地方
- D寄存器
- A寄存器
- OUTM
最终输出到哪儿是由操作指令的Destinatiion bits决定的
重置位输入
当按下重置键,程序就会从头开始运行
pc寄存器保存下一个执行的指令的地址
② Data Memory
③ Instruction Memory ROM
3. NandGame
CPU整体是由Combined state
,Instruction decoder
,Control Unit
,ALU
,Program engine
组成的
① Combined state 复合存储器
处理器有2个级别的存储:寄存器和RAM。
就目前位置,RAM的容量是最大的。但因为我们需要保存读取RAM所用的地址,而且需要存储中间数值,两个寄存器就派上用场了:寄存器A(用于地址)以及D(用于数据)。
现实世界中的处理器可以有几十个寄存器甚至更多;这里我们的处理器只有两个,因为这大概是可以做一个正常运作的处理器的最小数目。
a
, d
, *a
标志位和X
输入被用来更新一或多个寄存器,cl
是时钟信号。
flag | |
---|---|
a | 将X写入A寄存器 |
d | 将X写入D寄存器 |
*a | 将X写入RAM中由A寄存器所指定地址的位置 |
标志位可以联合使用,这样X将被同时写入多个寄存器中。如果所有的标志位都是0,那么X就被忽略掉。
输出 | |
---|---|
A | A寄存器的当前数值 |
D | D寄存器的当前数值 |
*A | 在RAM中A寄存器所指定地址位置的数值 |
② Instruction decoder
指令
处理器的工作是处理指令系列-就是程序-每次一个指令。 每个指令是一个16位的代码,指挥处理器进行某种操作。在指令中说明了:
- ALU完成的数学计算 - 如加法、自增和取反。
- 从哪里获得输入(寄存器或RAM)
- 向哪里存放结果(寄存器或RAM)
- 如果处理器需要跳转执行程序的不同位置,那么在指令里指定条件 - 如果操作的结果复合条件,就触发一个跳转。
- 除此之外,还有数据指令:从程序中读取一个数值到存储器中。 如果第15位为0,那么这条指令将一个数字读到寄存器A中。
汇编语言
使用二进制机器指令写程序十分麻烦。 因此,程序员们使用汇编语言,来用易于阅读的方式表示指令。 比如,二进制指令1110011111010000是汇编语言中的D+1→D, 意思是计算D+1,然后将结果存储在D中。
③ Control Unit
控制器实际执行指令, 它读取解码后的指令,然后操控ALU和存储器执行特定的操作
输入
- I是一个需要解码和执行的指令
- cl是时钟信号。
操作
需要执行由op标志位给出的ALU操作。
- ALU的X输入是D寄存器。
- Y输入取决于sm (存储器来源)标志位:
sm | Y |
---|---|
0 | 寄存器A |
1 | *A (RAM) |
存储
需要将数值存储到存储器中。 存储的数值取决于ci(计算指令)标志位:
ci | 需要存储的数值 |
---|---|
0 | 放在指令中的W(数据字) |
1 | ALU操作的输出 |
数值将被存储在由dst(目的地)标志位指定的存储器位置中。
输出
- j表示ALU的输出是否满足cd标志位所指定的条件
- A是寄存器A现在的数值。
④ Program engine
程序引擎包括一个存储程序的ROM模块,一个计数器(被称作程序计数器,英文缩写PC)在保存现在正在执行指令的地址。
Rom
ROM(只读存储器)是一个可以像RAM一样被寻址的存储单元,但是那里的数据只能读取不能改变。 通常ROM里的数据需要在出厂时烧录好。 简单的计算机就将程序放在ROM中;而更高级的计算机将程序放在硬盘这样的存储器中,然后在执行前加载到RAM中。 在本游戏中,我们使用一个ROM程序,这样就能避免将程序载入内存的麻烦。
程序计数器
这里的计数器叫做程序计数器或者PC,因为它数的是程序中的一条一条指令。 计数器的值就是需要执行的指令地址。 (通过j和A输入)改变计数器的值会让程序产生跳转
输入
- 如果j (跳转)是1,那么计数器的值将被设置成Ad(地址)中的数字。
- 如果j是0,Ad将被忽略。
- cl是时钟信号。
输出
- 由计数器中的地址指定的、存储在ROM中的指令