计算机系统 003 - 硬件体系

上一篇 计算机系统002 - 数值运算


前一篇中粗略讲述了二进制加法运算的过程,其中假定数据是从寄存器直接装载到加法器两端,加法器产生的结果也一样保存在另外一寄存器中,而没有在乎数据是如何从外界传递到了寄存器里,也并未给出寄存器中结果将以何种方式呈现给加法操做的真正用户。 程序员

所以本章将从计算机体系结构入手,介绍天然语言与机器语言间的共识。 算法

1. 问题表现形式

当咱们但愿求助他人帮忙解决某一问题时,首先要作的是用双方共同支持的天然语言(如普通话、英语)来描述问题,等待对方提出解决问题的方法或是协同完成。然而若是但愿将某一任务交付给计算机来完成,那么很抱歉,计算机并不会思考,他只是流程的接收和执行者,也就是说,如何造成流程,仍然须要咱们来完成。 数组

也可能有人会讲,不是啊,当我打开计算机,双击一个视频文件,计算机就会帮我播放,我并无告诉它如何播放,用什么播放吧。但你回过头来看看这段文字,就能够发现其中仍是含有通用流程,和你要寻找食物必须打开冰箱同样。至于视频播放的真正过程,后面会讲到,此处先给一个概念。 架构

全部的信息都是以电信号存储于存储器中,读取后获得的是二进制字节流,至于该字节流描述成什么具体内容须要依赖上下文,以及解释器。好比一样一句“很差吧”使用不一样语气,对于不一样接收者而言可能获取到不一样的含义。一样,一串字节流,使用音频播放器可能被解析为声音,使用notepad可能被处理为文本,甚至若是想象力再丰富一点,也能够假象成这是一个文字解密游戏。
所以一般会在字节流中埋下一些记号,标明数据类型,这些称为元数据。在元数据基础上,不一样视频格式会有不一样数据组合方式,经过枚举不一样格式尝试解析视频文件,如能够匹配为某格式,就按照该格式进行播放;如不能,则报错不能正确播放某文件。
模块化

综上所述,要想托管任务给计算机执行,那么计算机必须有两个充分条件: 函数

  • 接收任务描述:支持以程序(流程)方式表述处理过程
  • 具备运行能力:可以执行程序

计算机可以执行的任务归根结底是数学计算,而对于如何进行统1、可行的任务描述,人们作了大量尝试,直到图灵机概念的出现。 post

1.1 图灵机

图灵为了给出计算机的清晰数学描述,他观察人们计算式采用的方法和行为,而后将其抽象成一种统一的表达机制。图灵将人们用纸笔进行数学运算的过程抽象成下列两种简单动做: 性能

  • 在纸上写上或擦除某个符号
  • 把注意力从纸的一个位置移动到另外一个位置

为了模拟人的运算过程,图灵造出一台假想的机器,该机器按照读取规则读取纸带上数值,而后进行计算。
操作系统

这台机器主要由以下几个部分组成: 翻译

  • 一条无限长的纸带TAPE
  • 一个读写头HEAD
  • 一套控制规则TABLE
  • 一个状态寄存器

简而言之就是TABLE中规则控制读写头HEAD在无限长纸带TAPE上读写,根据读写内容进行运算,并选择是否保存结果至纸带特定位置中。如运行过程当中发生状态变化,则保留在状态寄存器内。

1.2 七层转换

图灵机是思想指导,回归到实践而言,对于任务描述的方法可表达为七层转换。《计算机系统概论》1.7节中提出,要控制电子器件按照咱们的意图工做,需经历以下七个完整过程:

  • 6 问题
    一般咱们采用“天然语言”来描述问题,如英语、汉语等,存在的问题是有不少语言组成部分具备二义性,而计算机指令极可能由于没法肯定语句的准确含义而采起错误措施,致使错误结果。所以,剩下的几层转换,都可以视为消除二义性的步骤。

  • 5 算法
    算法描述的特定是流程化、步骤清晰,并确保该流程能终止。具体以下:

    • 肯定性,代表每一个操做步骤的描述是清晰的、可定义的
    • 可计算性,表示每一步的描述均可被计算机执行
    • 有限性,表示过程是会终止的
  • 4 语言(开发语言)
    有了人类能够理解的计算方法,还须要转达计算机如何计算。计算机只能识别“机械语言”,这种语言具备严格的顺序方式,以便让计算机顺序地执行指令序列。这一层的语言一般称为开发语言,如C/C++,Java,Python等,因为开发语言须要程序员编写,所以仍具备必定可读性。

  • 3 机器(ISA)结构
    然而到开发语言一层仍然不够,由于开发语言多是面向多种硬件环境的,为了在特定的硬件平台上也可以顺利执行,还要作一次翻译,即将程序由开发语言翻译成为特定计算机的指令集。该部分功能一般由“编译器”或“解释器”来完成。

指令集结构实际上就是程序和计算机硬件之间接口的一个完整定义。

  • 2 微结构
    有了接口,就能够顺利完成任务描述,而真正要调动硬件的运行能力,还须要将各接口进行实现。好比不少处理器都使用了ISA X86,但具体实现却能够各不相同。

  • 1 电路
    微结构的概念最终要落实到一组组简单的逻辑电路,一样一个功能,如加法器,可使用多种实现方式,不一样的实现方式也一样带来了性能和成本上的差别。须要设计者从全局上进行衡量取舍。

  • 0 器件
    最后,相同的逻辑电路也仍然可使用器件技术来实现,如材料、规格等等。

综上所述,从人类天然语言表述的问题到最终执行的单元器件,须要作七层转换。对于为何要分层以及为何是七层,一般来说,高层一般是低层的抽象结果,意在忽略部分无关细节,提供分析问题的更高层次的视野。不过到目前为止表述的方法都是理论性的,接下来就看一下历史中实践的结果。

2. 冯·诺依曼结构

冯·诺依曼结构是一种将程序指令存储器和数据存储器合并在一块儿的电脑设计概念结构,它用于实现通用图灵机和一种相对于并行计算的序列式结构参考模型。

接下来咱们对冯·诺依曼结构进行细化,以下图所示。


从图中能够看出,冯·诺依曼结构主要有以下5个组成部分:

  • 内存
    内存存放程序,访问内存的第一步,是想内存提供被访问内存单元的地址。以读写操做为例:

    • 读:将访问内存单元的地址放入MAR;发送读信号通知内存;内存将该单元中存放的数据传送至MDR
    • 写:将访问内存单元的地址放入MAR;将要写入的数据放入MDR,发送写信号通知内存
  • 处理单元
    ALU所能处理的量化大小一般称为计算机的字长,如X86,X64。设计中一般会在ALU附近配置少许存储器,以便存放最近生成的中间计算结果。

  • 输入
    经过计算机解决问题的前提是可以将问题描述成电信号,转换层次可参考1.2小节。

  • 输出
    计算结果要具备可读性就必须经过设备进行输出,或是显示器、或是音响等可将电信号转换为天然语言的设备。

  • 控制单元
    控制单元负责指令的有序执行,其中具备两个特殊寄存器。

    • 指令寄存器(IR),保存当前执行的指令
    • PC寄存器,指示下一条待处理的指令,也可视为“指令指针”

哈佛结构
虽然冯·诺依曼结构是现代计算机的主要结构,但咱们也必须知道,还有一个结构叫作哈佛结构。它和冯·诺依曼结构之间最大的差别在于数据在内存中排列方式。冯·诺依曼结构中容许指令和数据混合存储在同一存储模块中,而哈佛结构必须使用独立的存储模块来分别存储指令和数据。

2.1 硬件实现(0 器件,1 电路)

本系列的第一篇中主要介绍了电学知识,为的就是在理解计算机时可以造成完整通路,而不是只能触及操做系统这一层,视底层硬件为黑盒,不知因此然。从前面咱们知道硬件只能识别电信号,不管是组合逻辑电路仍是时序逻辑电路,输出的产生终归须要输入的参与,而在托管任务时,任务就是咱们须要的输入。

然而咱们不可能在托管任务后还要守在一旁切换电信号以提供准确输入换取输出,既不高效也不可理智。所以最好能将任务描述使用一种可以最终转换为电信号的语言进行描述,而硬件在收到任务描述后,根据其中规则和数据自动完成计算,产出结果。同时为了保证任务描述的精确性,对于电信号咱们进行了一次抽象,将信号幅度抽象成有无,对应为0和1,即所谓的二进制。

2.2 指令结构及实现

冯·诺依曼结构在现有基础上提出计算过程应该是:程序和数据都是以bit流的方式存放在计算机内存中,程序在控制单元的控制下,依次完成指令的读取和执行。

二进制在历史悠久的人类天然语言面前是过于苍白的,为了可以将二进制位和人类想表达的操做对应起来,这一次,抽象的任务落在了天然语言上。既然计算机实质上是负责计算任务,所以能够不直接参考天然语言,而是选择抽象数学运算的基本规则(如加减乘除),造成指令。

目前通用计算机中指令是其执行的最小单位,指令自己自己由操做码和操做数组成。操做码标明其行为,操做数标明行为做用对象。
指令集架构还定义了其余内容,现存的指令集结构也各不相同,如Intel和AMD系的。但一般一条指令包含内容以下:

指令的处理过程是在控制单元控制下一步步完成的,这里执行的步骤顺序称为指令周期,每一步称为节拍,一般一个指令周期包含6个节拍,分别以下:

  • 取指令FETCH
    从内存中读取下一条待执行的指令,并将其装入控制单元的指令寄存器IR中。

    • 将PC寄存器的内容装入MAR寄存器
    • 该地址对应内存单元的内容(即下一条指令)被装入MDR
    • 控制单元将MDR内容装入IR寄存器
    • PC寄存器内容自增
  • 译码DECODE
    译码操做的任务是分析、检查指令的类型,并肯定对应微结构操做细节。


    换句人话就是将几个信号经过们电路扩展为多个单个信号,表明多个模式,而译码器后的器件可根据不一样模式执行预设的不一样操做。

  • 地址计算EVALUATE ADDRESS
    如操做数不是当即数(如123),而是寄存器地址等涉及寻址的表达方式时,须要进行地址计算以获得操做数的真正地址。
    寻址方式一般有以下几种:

当即寻址 操做数为当即数 MOV BX,8080H
寄存器寻址 操做数为寄存器 MOV BX,AX
直接寻址 操做数为地址 MOV AX,[1234H]
寄存器间接寻址 操做数为SI/DI/BX/BP之一 MOV BX,[DI]
寄存器相对寻址 操做数为SI/DI/BX/BP之一,加上偏移量 MOV BX,[DI+100H]
基址加变址寻址 操做数是BX/BP之一,加上SI/DI之一 MOV BX,[BX+DI]
相对基址加变址寻址 操做数是BX/BP之一,加上SI/DI之一,加上偏移量 MOV BX,[BX+DI+100H]
  • 取操做数FETCH OPERAND
    读取指令处理所须要的源操做数,分为两个步骤:

    • 将地址计算节拍中结果值装入MAR
    • 从MDR中获取读自内存的源操做数
  • 执行EXECUTE
    负责指令的执行操做,不一样操做码在该节拍的操做也各不相同。

  • 存放结果STORE RESULT
    将执行结果写入目的寄存器,该节拍结束后,循环进入第一个取指令节拍,因为PC寄存器在连续空间内指令上移动,所以也称为顺序执行。有顺序执行天然就有非顺序执行,这里不去深究跳转的具体实现,只要知道,知足条件后须要跳转前,将会修改PC寄存器中内容,跳转完成后,继续顺序执行连续指令,直到下一次跳转的来临。

2.3 从问题到开发语言

终于如今有了指令集,它定义了处理器能够执行的全部操做,而咱们剩下要作的就是将问题描述成一条条顺序或条件控制的跳转执行指令。对于简单的、小规模的任务,经过编写汇编函数,一般也能实现功能,除了效率略低,移植性不佳(平台支持的指令集可能不一样)等。但对于复杂、大规模的任务,使用指令集语言就略显力不从心了,毕竟全部操做如MOV等都须要当心翼翼地不停叮嘱,这时候人们又想到了抽象。

虽然指令集接口各家、各平台互不相同,那能不能想出一套更高层次的,不在乎平台差别的开发语言来描述问题。这样一来,还能够顺便把一些繁琐的、啰嗦的地址处理指令模块化,将任务描述这件事情从细节中解脱?答案是确定的,如今咱们有了更贴近底层的C/C++,主打一次编译到处运行的Java,甚至不要编译纯靠解释器在运行时逐字逐句翻译的Python等脚本语言,这些都让咱们可以更关注问题自己,而不是事无巨细的实现。

固然从开发语言到指令集并非省略了那些繁琐的细节,而是经过编译器、解释器、虚拟化运行环境等模块代劳。软件开发中有一句话和东北烧烤哲学相似,没有什么问题是一顿烧烤不能解决的,若是有,那就两顿;一样没有什么问题是一个中间层不能解决的,若是有,那就两个。

3. 总结

到目前为止,咱们阐述了从问题自己出发,造成任务描述(指令),并由电路执行运算。这些都是总体的概念,或者说,对于实现细节,都是作了较多的抽象,为的是从宏观上有所了解。后续将对体系中各组成部分进行分别深刻,力求浅出,再不济也要知道一些关键概念。

这里或者本系列也均不会进行任务无谓的语言之争,本系列文章寻求的是问题的解决方法、思惟,而不是各实现细节之间的差别。

追寻知识融会贯通后的快感。

相关文章
相关标签/搜索