深入理解计算机系统(4.2)---硬件的魅力

引言

  这个系列已经很久没更新了,记得上一篇博文已经是三月份了,实在是抱歉。最近业余时间没有以前充裕了,因此更新一篇博文已经变成了一种奢侈。记得以前刚开始写的时候,最多的时候LZ一天写过3篇博文,现在想想,往事如梦。

  好了,好不容易写一次,就不多说废话了,本文主要介绍一下硬件以及HCL语言的内容。

从疑问开始

  首先,在介绍本文的内容之前,我们先来思考一个看似简单,却实际比较“高深”的问题。众所周知,计算机归根结底是在和0、1打交道,那么到底0和1是如何被计算机记住的呢?

  怎么样,这个问题是不是有点像数学界的1+1为什么等于2?是否瞬间感觉自己很高大上?

  请稳住,其实这个问题的答案比1+1=2要简单多了。答案就是计算机通过电压来记录0和1。在学习物理的时候大家肯定都听说过电压这个东西,它的单位一般是伏特(V)。比如我们常用的电压一般是220V。计算机当中使用1V来代表1,使用0V代表0。

  解答了这个问题,接下来我们就可以继续我们的设计之路了。

设计的基础

  要谈设计,就要知道设计的基础。刚才其实我们了解了最基本的基础,就是0和1如何表示,不过这只是最根本的立足之本,我们还需要一些基本的元素。就像你要画一个物体一样,首先是点,然后才能点动成线,进而线动成面,最终面动成体。

  刚才的0和1只不过是点而已,接下来,我们要用点变换成线。这个东西就叫做逻辑门。

  逻辑门是数字电路的基本计算元素,也可以看做是物理结构与逻辑结构的映射,它们实际上是由晶体管组成的。逻辑门接受信号的输入,并根据信号产生一定的输出,而输出则是输入的布尔函数,也就是说,输出只能是0或者1。下图是and门(‘与’门)、or门(‘或’门)和not门(‘非’门)的标准符号,你可以看做它们代表了一组线路的组成方式。

  and:               or:                not:

  

  可以看出,and和or都是2个输入,而not为1个输入。前面我们提到了HCL硬件设计语言,上面的三个图分别用HCL表示则是,a&&b、a||b以及!a。

  举个例子,比如对于and门来说,它接受2个输入,如果2个输入都是高位电压,则输出的为高位电压,也就是输出为1。否则的话,都是输出低位电压,也就是输出为0。这些就是建立在刚才1V为1,0V为0的基础之上的。

  

高级设计

  现在我们已经掌握了基础,那么在基础之上,我们就可以玩点花样了。比如刚才所提到的逻辑门,它们只能接受1位的输入和1位的输出,比如我们可以计算0&&1为0。那如果我们希望计算更加复杂的表达式该如何做呢,比如10001&&11111=?(注意,这里是位‘与’运算,而不是逻辑运算)。

  答案就是组合电路。道理很简单,一个逻辑门可以计算1位,如果我们弄来32个逻辑门,不就可以计算32位了吗?那么像上面那个10001&&11111的运算,我们就可以采取5个逻辑门去计算。当然,实际上并不是这样的,这个后续我们会更加详细的介绍。

  不过电路往往是复杂的,不能随便乱接,否则电死了谁负责?因此组合的电路需要遵循以下两个原则。

  1、两个逻辑门的输出不能连接到一起,否则它们可能会使线上的信号矛盾,因此可能会得到一个不合法的电压或故障。比如1个0V和1个1V接到一起,会不会出来个0.5V,又或者类似于正负极相接,直接短路了呢。

  2、组合的电路必须是无环的。也就是说输出不能再当做输入,否则会使这个函数产生歧义。这个道理很简单,比如数学上来说,如果c=a+b。我们这里可以把c看做输出,a和b看做输入。如果a又等于c了,那么是不是b就等于0了呢?当然不是,因为a此时其实是a+b,第二轮的c又会等于a+2b,同理,第三轮的c又会等于a+3b。那么到底c=a+b还是c=a+2b还是c=a+3b?(这里有点绕,请各位猿友仔细品味)

  遵循以上原则,我们就可以随意组装电路了。比如在书中的这个电路。

  它代表着输出是a和b是否相等,如果用HCL来描述电路,就是(a && b) || (!a && !b)。我们不难看出来,这个表达式就是编程语言当中的a == b。

  接下来这个图是另外一个书中的例子,它被翻译为多路复用器。其实之所以叫这个,就是因为其中的控制位s是可以复用的。如下图。

  在这个例子当中还不是特别明显,但是之后有更明显的例子说明“复用”的含义。以上这个电路如果用HCL表达,则是(a && s) || (b && !s)。这个电路的含义是如果s为1,则结果为a,否则结果为b。

  在书中对HCL表达式与C语言的表达式做了区分,有以下三点。

  1、逻辑门是持续输出的,但C语言表达式是执行到的时候才会求值。这个区别可以把逻辑门当成一个电路来看,电路是不能断电的,电流会一直存在。

  2、C语言中输入可以是任意整数,而HCL只能是1和0。这点比较好理解。

  3、对于a && b这个符号来说,C语言中的规定是如果前者为假,则后者不会再计算。而HCL当中没有这种说法。

按位计算

  以上所提到的,哪怕是高级设计,也依然是针对1位进行操作的。那么如何才能真正操作多个位呢,比如平时常用的32位或者64位。

  道理很简单,就是多个1位操作一起进行,例如下面这个图。

  这个图当中每个位相等的判断都是上面所提到的两个not门,两个and门和一个or门组成的组合电路。它们并列的一起进行,最终再通过一个and门,就完成了判断两个32位的数字是否相等的操作。也就是表达式A == B,值得注意的是,这里的A和B都是32位的。

  还有一种类似于C语言中switch语句的表达式,就是如下形式。

  

  它代表的意思就是如果s为1,则输出A,否则输出B,同样,这里的A和B都是32位的。那么使用电路如何表达呢?其实就是上次的复用电路的32位版本。如下图。

  可以看到,s的not值是被复用的,否则的话,这里需要32个not门。值得一提的是,HCL中条件选择表达式中的条件是不需要互斥的,只是按照优先顺序依次选取,这与C语言中的switch是不同的。

  最后一种HCL表达式,是集合的形式。它表示需要拿一个输入信号与某些值做匹配。比如下图当中的S1和S0。

  其中如果S1为code == 2 || code == 3,S0为code == 1 || code == 0。那么HCL可以用另外一种方式表达,即code in {2,3}和code in {1,0}。可以看出,HCL表达式其实就是一种硬件表述方式。

  

存储器和时钟

  上面我们介绍的都是组合电路,它们的作用是根据输入来产生一个值。但是刚才也说过,组合电路是一直持续输出的,因此它无法保持一个状态不变。但我们的计算机是需要存储数据的,因此就需要能保存状态的存储设备。存储设备则是由一个时钟控制,时钟就像一个开关一样,它控制着存储设备什么时候更新设备里的值。

  常用的存储设备一般有两种。

  1、时钟寄存器:存储单个位或者单个字。时钟信号来控制寄存器是否要加载输入的值。

  2、随即访问存储器:存储多个字。用地址来选择该读、写哪个字。

  时钟寄存器的典型应用是PC、条件码寄存器以及程序状态。它们都有明确的输入,这意味着它们的值其实是某几个值的一个函数,比如条件码寄存器的输入主要就是逻辑计算单元的值,因此条件码寄存器的值就可以看做是逻辑计算单元的函数。

  时钟寄存器一般是根据时钟信号来更新状态的,而时钟信号就像一个表一样,比如每到12点,寄存器的值就更新一下。就像下面的图示一样,当时钟变化时,值就会变化y。

  随即访问存储器最典型的例子就是我们的寄存器文件(也就是8个程序寄存器)和随即访问存储器(也就是我们常说的内存)。它们没有明确的输入值,因此不存在函数关系。不论是寄存器文件还是内存,都有读和写两种操作,而对于时钟寄存器来说,是无所谓读和写的,因为它只会根据输入的变化改变输出的值,是可以直接连接到电路上去的。

  寄存器文件一般有两个读端口和一个写端口。每个端口都附带一个地址来标识操作的是哪个寄存器,而对于写端口,还有一个输入数据,对于读端口,则还有一个输出数据。具体的图示如下。

  可以看到在寄存器文件的写端口处,有一个时钟(clock)控制着写的操作。当时钟变化时,输入数据的值将会更新到对应的寄存器当中。而对于读数据,则类似于组合电路,根据输入的地址值(src),寄存器文件会输出相应的数据。

  对于随即访问存储器来说,与寄存器文件非常相似。不同的是,随即访问存储器只有一个地址输入,而不是三个,只有一个数据输出而不是两个。具体的图示如下。

  当地址(address)输入,并且输入数据(data in)输入时,如果写(write)输入为1并且时钟(clock)变化时,存储器中地址为输入地址值的值将会变化,值就是输入数据(data in)的值。同样的,如果地址(address)输入,并且写(write)输入为0,则输出数据(data out)会输出地址为输入地址值的值。这里还有一点特殊的是,当读数据的时候,如果地址超出了范围,error信号将会输出为1。回忆一下刚才的HCL语言,error其实就可以看做是一个组合电路的输出,等于(address in > max address ) || (address in < 0),即当输入的地址值不在合法范围内时,它的输出为1。

小结

  回忆一下本章的内容,其实就是结合HCL语言在讲硬件的组成。而这些硬件,就是Y86处理器需要使用的。比如组合电路,存储器。到本章最后的时候,已经非常接近我们的编程领域了,可以看到有寄存器和内存的出现。但要注意的是,这里的寄存器文件并不等于寄存器,随即访问存储器也不等于内存,LZ只是想让各位猿友更形象的去理解它。

  下一章,就是带着大家一起做一个顺序实现的Y86处理器,这是一个非常低级但却最基础的处理器。如果你慢慢的进入了这个世界,你会觉得这是一件非常有意思的事情。就LZ本身来讲,读这本书的时候,最大的感受就是,每一章刚开始读的时候都非常枯燥无味,但每当读了几节以后,就有种豁然开朗的感觉,这种感觉相信你一定也非常喜欢。

  最后LZ再说明一下,本系列博文都是LZ在自己理解的基础上写的,因此尽管核心内容与原著相似,但语言描述上差异甚大,如果各位猿友看着不习惯的话,不妨去看看原著,或许会有不一样的收获。

深入理解计算机系统(4.2)---硬件的魅力,布布扣,bubuko.com

时间: 2024-09-04 10:23:07

深入理解计算机系统(4.2)---硬件的魅力的相关文章

《深入理解计算机系统》第六周学习笔记

第四章 处理器体系结构 (一)知识点总结 一.Y86指令集体系结构 1.Y86处理器状态类似于IA32,有8个程序寄存器: %eax.%ecx.%edx.%ebx.%esi.%edi.%esp.%ebp.处理器的每个程序寄存器存储一个字.%esp被入栈.出栈.调用和返回指令作为栈指针. 2.3个一位的条件吗:ZF.SF.OF,它们保存最近的算术或逻辑指令所造成影响的有关信息.程序计数器PC存放当前正在执行指令的地址. 3.程序状态的最后一个部分是状态码stat,它表明程序执行的总体状态 4.Y8

深入理解计算机系统读书笔记一 ---&gt; 计算机基础漫游

一.程序编译的不同阶段. 通常我们是以高级程序开发易于阅读的代码,我们通过语法规则推断代码的具体含义.但是计算机执行代码的时候就需要把代码解析成既定的可执行问题,计算机是如何处理的呢?这里以C语言hello.c文件为例来说明中间过程. #include <stdio.h> int main() { printf("hello world!\n"); } 先上张图. C语言源程序----预处理解析头文件和函数  --- 编译器解析成汇编语言 ---   翻译机器语言指令,打包

深入理解计算机系统(1.1)------Hello World 是如何运行的

上一篇序章我谈了谈 程序员为啥要懂底层计算机结构 ,有人赞同也有人反对,但是这并不影响 LZ 对深入理解计算机系统研究的热情.这篇博客以案例驱动的模式,通过跟踪一个简单 Hello World 程序的生命周期开始系统的学习,包括它被程序员创建,到在系统上运行,输出简单的消息,然后终止.LZ 将沿着这个程序的声明周期,先简要的介绍一些逐步出现的关键概念.专业术语以及组成部分.后面将会详细展开. 1.计算机系统 我们知道计算机系统是由硬件和软件组成的.它们共同工作来运行应用程序.虽然系统的实现方式随

计算机编程基础之深入理解计算机系统1

目录 概述——<深入理解计算机系统> 计算机系统漫游 信息的表示和处理 概述——<深入理解计算机系统> Computer Systems A Programmers Perspective  英文名 计算机系统漫游 本章简介 当系统上执行hello程序时,系统发生了什么以及为什么会这样 信息就是位+上下文 源程序(或者源文件) hello.c,实际上是由值0和1组成的位(bit)序列,8个位被组织成一组,成为字节.每个字节表示程序中某个文本字符,大部分的现代系统都使用ASCII标准

深入理解计算机系统(3.1)------汇编语言和机器语言

<深入理解计算机系统>第三章--程序的机器级表示.作者首先讲解了汇编代码和机器代码的关系,阐述了汇编承上启下的作用:接着从机器语言IA32着手,分别讲述了如何存储数据.如何访问数据.如何完成运算以及如何进行跳转.通过这些步骤,又告诉了我们分支语句.循环语句是怎么完成的,函数调用.栈帧结构以及递归过程.最后能通过编译器产生的汇编代码表示,我们要了解编译器和它的优化能力,知道编译器能为我们完成哪些工作. 而这篇博客我们将讲解汇编和机器代码的关系.首先下面一张图是C语言.汇编语言以及翻译过的机器语言

深入理解计算机系统之旅(一)计算机系统漫游

1.计算机系统是什么? 我们直观的可以看到的计算机系统就是一台电脑,包括主机.显示器.键盘鼠标,然后显示器上会显示不同界面,用鼠标点击,键盘输入界面就会相应操作. 2.深入一点,他们是如何工作的? 计算机系统是由硬件和系统软件组成,它们共同工作来运行应用程序. 3.再深入一点,硬件是什么?系统软件是什么?应用程序是什么? 硬件是组成计算机系统的基础,大家耳熟能详的就是CPU.内存.硬盘.主板等. 系统软件是运行在硬件之上的一层控制软件,就是我们经常听到的Windows XP.WIN7.Linux

深入理解计算机系统读书笔记之第一章:漫游

我是从豆瓣上看到好多人都在推荐这本书,于是就去借来读一读,昨天晚上用了好长时间来读这本书的第一章节,感觉这本书比较符合我(有些基础还不太明白,这本书详细的进行了讲解,很好). 下面写一下我的理解(顺便回顾一下知识) 第一节主要讲的是: A Tour of Computer Systems 以hello.c为例进行讲解,介绍这个程序如何从一个源程序变成可执行程序,再到执行,显示屏上出现“hello,world” ···········································

《深入理解计算机系统(第三版)》第二章 信息的表示和处理

<深入理解计算机系统(第三版)>第二章 信息的表示和处理 ??计算机本身是由处理器和存储器子通过系统组成.在核心部分,我们需要方法来表示基本数据类型,比如整数和实数运算的近似值.然后,我们考虑机器级指令如何操作这样的数据,以及编译器又如何将C程序翻译成这样的指令.接下来,研究几种实现处理器的方法,帮助我们更好的了解硬件资源如何被用来执行指令.理解了编译器和机器级代码,我们就能了解如何通过编写C程序以及编译它们来最大化程序的性能.本章主要使我了解了如何表示和执行应用程序,通过一些技巧,来写出安全

《深入理解计算机系统》第四章 处理器体系结构

<深入理解计算机系统>第四章 处理器体系结构 我们看到的计算机系统都只限于机器语言程序级.处理器执行一系列指令每天指令执行某个简单操作,它们被编码为由一个或多个字节序列组成的二进制格式.在本章的学习中,我们主要了解ISA抽象的作用以及了解流水线和实现方式. 4.1 Y86-64指令集体系结构 字节序列转换为Y86-64指令的方法总结如下: 通过代码部分确定指令长度,从而以指令为单位划分字节序列: 通过功能部分确定具体的指令: 通过寄存器指示符字节确定指令中涉及的寄存器: 通过转换数值部分以小段