学习笔记(二):计算机的语言

计算机的语言



计算机语言中的基本单词称为指令,而一台计算机的全部指令称为计算机的指令集

对以前还是现在的计算机而言,“设备简单性”都是值得考虑的重要问题,而本章的目的就是介绍一种符合此原则的一种指令集,介绍它怎样用硬件表示,并怎样和高级语言之间相互转换。

介绍的指令集来自MIPS公司,是1980s以来出现的各类指令集的优秀代表之一。


计算机硬件的操作

任何计算机必须能够进行算术运算,MIPS汇编语言的下述记法:

Add a, b, c

这个代码表示将两个变量b和c相加,并将它们的和放入变量a中。

这种记法是固定的:每条MIPS算术执行一个操作,并且有且仅有三个变量。例如:要将b, c, d, e之和放入a中,则要以下几个指令:

Add a, b, c  #The sum of b and c is placed in a

Add a, a, d  #The sum of b and c is now in a 

Add a, a, e  #The sum of b, c, d and e is now in a 

这三条指令共同完成了四个变量的相加。

在上述代码的每一行中,符号“#”右边是注释,用来帮助人们理解程序,而计算机会自动忽略它们,与其他的高级语言不同的是,这种语言美韩只能有一条指令,而注释总是在一行结尾结束。

与加法类似的指令一般都有三个操作数:两个进行操作的数和一个保存结果的数。要求只有两个进行运算的数和一个保存结果的数,这样的设计原则符合了硬件设计的四条基本原则中的第一条:简单源于规整。这样的原则不会给硬件设计带来更大的复杂性。

下面介绍一下其他常用的MIPS汇编语言。

Add $s1, $s2, $s3  表示将$s2和$s3的和放入变量$s1中

Sub $s1, $s2, $s3  表示将$s2和$s3和差放入变量$s1中

Addi $s1, $s2, 20  表示变量和常数之间的相加

Lw $s1, 20 ($s2)  表示将内存中的一个字加入到寄存器$s1中

Sw $s1, 20 ($s2)  表示将寄存器中的一个字加入到内存$s1中

这是一些常见的MIPS汇编语言,之后的内容中会向大家介绍更多指令,有逻辑指令和条件分支指令和无条件跳转等。

举例:将C语言中赋值语句编译成MIPS语句

以下是C语言中的两个语句:

a= b + c

d= a – e

将上两个语句转换为MIPS代码

十分简单,用add和sub就可以解决:

Add a, b, c

Sub d, a, e

下面我们来看一个复杂一些的:

F= (g+h) – (i+j)

因为MIPS指令只进行一个操作,所以我们要把这个语句分成几个指令来进行,而由于中间计算出来的结果要暂时寄存在一个地方,我们要创建一个临时变量,我们可以把它叫做t0:

首先要把g和h的值相加放在临时变量t0中,

Add $t0, g, h #temporary variable t0 contains g and h

然后要把i和j的值相加放在临时变量t1中

Add $t1, i, j #temporary variable t1 contains i and j

最后再用临时变量t0减去t1然后再把结果放入变量f中就可得到最终结果

Sub f, $t0, $t1 # f get t0 – t1, which is (g + h) – (i + j)

在遇到这种问题时,大家可以一步一步的分析,这样就会变得十分简单。


计算机硬件的操作数


不同于高级语言程序,算术运算指令的操作数是有限的,他们必须来自寄存器。寄存器由硬件直接构建,数量有限,是计算机硬件设计的基本元素。在MIPS体系结构中寄存器大小为32位,由于32位大小的寄存器经常出现,我们把它叫做一个“字”。

高级语言的区别就是,寄存器的数量是有限的。MIPS中有32个寄存器,而这正可以表示为硬件设计四条基本原则中的第二条:越少越快。

大量的寄存器可能会使时钟周期变长,但是这也不是绝对的,31个寄存器并不见得比32更快。在MIPS约定书写指令时,用一个$符号后面跟两个字符来表示一个寄存器如$t0, $t1等。


储存器操作数


在计算机中,寄存器只能保存少量的数据,绝大多数数据都是保存在储存器中的,所以MIPS必须包含在储存器和寄存器之间传送数据的指令,这些指令叫做数据传送指令。为了访问储存器中的一个字,指令必须给出存储器地址,存储器就是一个很大的下标从0开始的数组,地址就相当于数组的下标。

将数据从存储器拷贝到寄存器的数据传送指令叫做取数指令,也就是我们之前提到过的lw (load word)。

例题:设A是一个含有100个字的数组,编译器将寄存器$s1, $s2分配给变量g, h。设数组A的起始地址,或称基址,存放在寄存器$s3中。试编译下面的C语句:

G = h + A[8]

因为A的基址在$s3中而且我们要将A[8]传送到寄存器中,A[8]的地址就是基址再加上它的元素序号8,我们可以把取回的数据放在一个临时的寄存器中,代码如下:

Lw $t0, 8, ($s3) #Temporary reg $t0 get A[8]

这之后就很简单了,我们只需将含有A[8]的临时寄存器和h相加,就可以得到结果:

Add $s1, $s2, $t0 #g = h + A[8]

很多程序都会用到字节类型,且大多体系结构按字节编址。因此,一个字的地址必和它所包括的四个字节中某个的地址相匹配,且连续字的地址相差4(一个字33四个字节)。例如字的地址为0,1,2,3,则字节地址为0,4,8,12。在MIPS中,字的起始地址必须是4的倍数,这叫对齐限制,许多体系结构中都有这样的设定,而具体原因我会以后向大家介绍。

有两种字节寻址的计算机:一种使用最左边的“大端”字节的地址作为字地址,另一种用“小端”字节的地址作为字地址。MIPS采用大端编址。

让我们来看一个例题:

假设变量h存放在寄存器$s2中,数据A的基址放在$s3中,试编译下面的C语句:

A[12] = h + A[8]

这道例题的意思就是将数组A取出加上变量h然后再存入数组A中,但是我们要注意的是:因为对齐限制,字的起始地址必须是4的倍数,也就是说我们要把地址全部乘4。先进行的是取数的动作:

Lw $t0, 32, ($s3) #Temporary reg $t0 gets A[8]

然后再进行h + A[8]的动作:

Add $t0, $s2, $t0 #Temporary reg $t0 gets h + A[8]

最后一条指令使用48(4*12)作为偏移量,寄存器$s3作为基址寄存器,将加法结果存放到存储器单元A[12]中:

Sw $t0, 48, ($s3) #Stores h + A[8] back into A[12]

许多程序的变量个数要远多于计算机的寄存器个数,因此,编译器会尽量将最常用的变量保持在寄存器中,而将其它的变量放在储存其中,方法是使用lw/sw指令在寄存器和存储器之间传送变量。将不常使用的变量存回到存储器中的过程叫做寄存器溢出。


寄存器相比于存储器有以下几个优点:

寄存器一定比存储器快,因为寄存器的数量更少,因此访问寄存器中的数据要远快于访问存储器中的数据。

寄存器中的数据更容易利用。一条MIPS算术运算指令能完成都两个寄存器,对他们进行运算,并写回运算结果的操作。而一条MIPS数据传送指令只能完成读一个操作数或写一个操作数的操作,并且不能对它们进行运算。

寄存器与存储器相比,访问时间短,吞吐率高,寄存器中的数据访问速度快并易于利用,访问寄存器相对于访问存储器功耗更小,因此,为了获得高性能和节约功耗,编译器必须高效的利用寄存器。

常数或立即数操作数


在程序中会经常在某个操作中使用到常数,如果仅从之前用过的指令来看,如果要使用常数必须现将其从存储器中取出:

Lw $t0, AddrConstant4 ($s1) #$t0 = constant 4

Add $s3, $s3, $t0 #$s3 + $t0 ($t0 == 4)

但是我们有避免使用取数指令的办法:专门的立即数算术运算指令:addi(add immediate),这样,上述的操作只需写成:

Addi $s3, $s3, 4 #$s3 = $s3 + 4

立即数算术运算指令说明了硬件设计四条原则的第三条:加速执行常用操作。常数操作数出现频率高,而且相对于从存储器中去常数,包含常数的算术运算指令执行速度快很多,而且能耗较低。


有符号数和无符号数


首先回忆一下计算机是如何表示数的:在计算机硬件中数是以一串或高或低的电信号来体现的,所有的信息都有二进制数位(binary digit)或位(bit)组成,因此二进制数运算基本单位是bit,取值可以使两种状态之一:1或0。

我们会在十进制数的右下角写上10,二进制数的右下角写上2。在一个32位数中,我们从右向左标记各位为0,1,2,3……31,而像数字1011(2)的存放位置就是:

0000  0000  0000  0000  0000  0000  0000  1011

由于字是水平或垂直方向向上书写的,用最左边或最右边表示大小带有不确定性,因此采用最低有效位表示最右边的一位(第0位),最高有效位标识最左边的一位(第31位)。

MIPS的字有32位,可以表示2**32个不同的32为模式,可以表示从0到2**32-1(4294967295)之间的十进制数:

0000  0000  0000  0000  0000  0000  0000  0000 = 0

0000  0000  0000  0000  0000  0000  0000  0001 = 1

0000  0000  0000  0000  0000  0000  0000  0010 = 2  

1111  1111  1111  1111  1111  1111  1111  1101 = 4294967293

1111  1111  1111  1111  1111  1111  1111  1110 = 4294967294

1111  1111  1111  1111  1111  1111  1111  1111 = 4294967295

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值