Chinaunix首页 | 论坛 | 博客
  • 博客访问: 85076
  • 博文数量: 34
  • 博客积分: 1640
  • 博客等级: 上尉
  • 技术积分: 395
  • 用 户 组: 普通用户
  • 注册时间: 2008-04-17 14:37
文章分类
文章存档

2008年(34)

我的朋友
最近访客

分类:

2008-04-17 15:44:30

这一章讲的主要就是计算机所使用的语言。也就是Instruction Set Architecture。我发觉在我学习计算机的整个过程中,语言的学习占了很多时间。每中语言就好像一种外语一样。其实,如果我真的对所有语言都花向我学英语一样的时间的话,那种语言我学不会呀。唉,可是我的英语水平还是不高。为什么呀?老天。 

计算机所使用的语言受到很多限制,也就是说这种语言实在是太低级了。与我们自然语言的差别那正是没法说了。我想,只要我们能够理解这些限制以及他们的缘由的话我们对该语言也应该了解的差不多了吧。计算机语言中的最小单位应该是Instruction吧。对于这种语言的设计是有很多原则的。通过了了解这些原则对我们理解整个语言的设计是很有帮助的。(真没想到我们也可以自己来设计语言了)。当然下面所讲述的一些内容只是正对MIPS这种语言而言的,对于其他的语言其包含的限制可能会不一样。但是这些语言的区别只可以算作是方言而已。因为,对于所有的计算机语言而言,他们都需要提供一些相同的基本的功能。不同之处只是在语言的形式上而已。

限制1: Every Instruction must have exactly three operands,No more, no less. 原理:Simplicity favors regularity。

限制2:the operands of arithmetic instructions must be from registers。并且the number of registers is limited (32)。 原理:Samller is faster。也就是说所有的算术操作只能是对寄存器进行计算。不能直接存取内存。

由于registers的数量是有限的,所以我们必须提供一种方法从更大的存储区域内存中存取数据的指令。这也是data transfer instructions的用途所在。另外,为了存取内存中的数据,我们必须指定我们要存取的内存中的区域,这也就是所谓的address的概念了。当然,对于任何集合,我们都需要提供一种表示其中元素的方式。只不过,在这里我们称这种方式为address而已。其实这是一个很形象的名字。在程序中,地址通常用在array或是structure中。对于array来说,每个array都必须有一个初始地址,成为base address。在程序运行时,每个array的具体的base address由compiler来决定。

上面讨论的无论是 register或是memory,都可以认为是变量。但是还有一种我们没有提到,就是constant。对于constant而言,它是非常普遍的。如果我们也将其放在内存中的话,不但会占用内存,还会增加一个存取内存的操作。一个更好的方法是将常量直接放在指令中。这样我们也就需要可以直接操纵 constant的指令。这又体现了另外一个设计原则:Make the common case fast.

记住一点,计算机中所有的一切都是有0和1来表示的,各种数据,以及指令。那么计算机又是如何来表示指令的呢?计算机中指令是由32为的0,1串来表示的。这个串里面必须有一部分来表示该指令所表示的操作,该指令的各种操作数,还可能需要表示地址等等。也就是说对于表示指令的32为我们一般都会分为几个部分,每一部分表示不同的意义。至于如何对他们进行划分这就是ISA设计人士的责任了。

在计算机中,除了算术操作之外,还有逻辑操作(and, or, not),移位操作(shift),关系操作(==, <, >)。看来我们所学的离散数学还是挺有用的,这里涉及到了布尔代数,数理逻辑,还有关系,等。 需要注意的是,关系操作主要用在条件跳转指令上。另外,在ISA中,并没有C语言中的loop命令。这个命令是由关系操作以及条件跳转指令来实现的。

在ISA提供了专门的指令来实现函数功能。为了实现函数,有ISA提供的机制有:1. 专门的register来存储参数以及返回值。2. 跳转到被调用函数callee的指令, 3, 返回调用函数caller的指令。为了能够记住caller的地址,一般计算机都用了一个PC寄存器,用于存放当前正在执行的指令的内存地址。当我们需要调用某个函数时,需要将当前的PC+4并存入存放返回地址的寄存器。当程序需要返回时,就是用一个从寄存器跳转的指令就可以了。

由于register个数是有限的,因此如果我们要求所有的函数的参数都存在寄存器里面的话,这就会对参数的个数存在限制。所以我们需要一种可以存放多余的参数。这个存放参数的地方也就是我们常说的Stack.另外,对于Stack我们提供了一个指向Stack的指针,也就是一个专用的register,sp,它指向当前Stack的顶部。另外,Stack还用于存放函数中的local variables。除了local variables,一般来说,程序中还有有一种变量也就是static variables。对于这些变量,也是有专门的区域来存放的,也就是所谓的static area,有的机器对这类区域也提供了支持,也就是添加了一个专门的寄存器,global pointer来指向这个区域的其实地址。在程序中,经常出现的另外一种变量,称作dynamic data structures。对于这类变量,内存中也有专门的区域来存放。对于这段区域,没有专门的寄存器。

根据上面的分析,一般来说,内存被分为以下几个部分:code area, static data, dynamic, data, stack。这里的排列是按照低地址到高地址来排列的。对于code area,我们有PC寄存器,对于static area我们有gp register,对于stack,我们有sp以及fp。

而机器中提供的指令一般可以分为:算术指令(add, subtract),数据传输指令(load, save),逻辑指令(and, or, not, shift),条件跳转(比较操作)以及非条件跳转(直接地址跳转,寄存器跳转,jump and link)。通过这些指令,我们基本上可以实现现在程序中的全部操作。注意的是所有的算术操作以及逻辑,比较等操作都是对寄存器而言的。而数据传输指令的作用就是在内存与寄存器之间交换数据。还有寄存器跳转,jump and link,以及PC一起使函数实现成为可能。



阅读(677) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~