目录

2.1 计算机硬件的操作数

2.1.1 存储器操作数

2.1.2 常数或立即数操作数

2.2 有符号数和无符号数

2.1 无符号数

2.2 有符号数

2.3 计算机中指令的表示

2.4 逻辑操作

2.5 决策指令

2.5.1 条件分支

2.5.2 循环

2.5.3 case/switch 语句

2.6 计算机硬件对过程的支持

2.6.1 过程使用更多的寄存器时

2.6.2 嵌套

2.6.3 在栈中为新数据分配空间

2.6.4 在堆中为新数据分配空间

2.7 表示字符串的方式

2.7.1  ASCII 码表示字符

2.7.2  Unicode 表示字符

2.8 MIPS 中 32 位立即数和寻址

2.8.1 32位立即数

2.8.2 分支和跳转中的寻址

2.8.3 MIPS寻址模式总结

2.8.4 机器语言解码

2.9 翻译并执行程序

2.10 ARMv7(32位)指令集

2.10.1 寻址模式

2.10.2 比较和条件分支

2.10.3 ARM 特色

2.11 ARMv8(64位)指令集

2.12 x86指令集

2.12.1 x86寄存器和数据寻址模式

2.12.2 x86 整数操作

2.12.3 x86 总结

2.13 谬误与陷阱


指令集:一个给定的计算机体系结构所包含的指令集合。

常见的指令集有MIPS、Inter X86、ARMv7和ARMv8。本书选择MIPS指令集来介绍。

存储程序概念:多种类型的指令和数据均以数字的形式存储于存储器中的概念。

下面是MIPS汇编语言指令:

MIPS操作数
名字 示例 注释
32个寄存器

$s0 - $s7,$t0 - $t9,

$a0 - $a3,$v0,$v1,

$gp,$fp,$sp,

$ra,$at,$zero

寄存器用于数据的快速存取。

在MIPS中,只能对放在寄存器中的数据执行算数操作。

寄存器$zero的值恒为0。

寄存器$at被汇编语器保留,用于处理大的常数。

 个存储器字 Memory[0],Memory[4],... ,Memory[4294967292]

存储器只能通过数据传输指令访问。

MIPS使用字节编址,所以连续的字地址相差4。

存储器用于保存数据结构、数组和溢出的寄存器。

*注:寄存器$s0,...,$s7常用来表示变量寄存器;寄存器$t0,...,$t9常用来表示临时寄存器。

MIPS汇编语言
类别 指令 示例 含义 注释
算术 加法 add $s1, $s2, $s3 $s1 = $s2 + $s3 三个寄存器操作数(有且仅有三个操作数,且必须在寄存器中选取)
减法 sub $s1, $s2, $s3 $s1 = $s2 - $s3 三个寄存器操作数
立即数加法 addi $s1, $s2, 20 $s1 = $s2 + 20 常用于加常数数据
数据传输 取字 lw $s1, 20 ($s2) $s1 = Memory[$2 + 20] 内存-->寄存器(一个字)
存字 sw $s1, 20 ($s2) Memory[$s2+20] = $1 寄存器-->内存(一个字)
取半字 lh $s1, 20 ($s2) $s1 = Memory[$2 + 20] 内存-->寄存器(半字)
取无符号半字 lhu $s1, 20 ($s2) $s1 = Memory[$2 + 20] 内存-->寄存器(半字)
存半字 sh $s1, 20 ($s2) Memory[$s2+20] = $1 寄存器-->内存(半字)
取字节 lb $s1, 20 ($s2) $s1 = Memory[$2 + 20] 内存-->寄存器(一个字节)
取无符号字节 lbu $s1, 20 ($s2) $s1 = Memory[$2 + 20] 内存-->寄存器(一个字节)
存字节 sb $s1, 20 ($s2) Memory[$s2+20] = $1 寄存器-->内存(一个字节)
取链接字 ll $s1, 20 ($s2) $s1 = Memory[$2 + 20] 取字作为原子交换的前半部分
存条件字 sc $s1, 20 ($s2)

Memory[$s2+20] = $1;

$s1 = 0 or 1

存字作为原子交换的后半部分
取立即数的高位 lui $s1, 20  $s1 = 20* 取立即数并放在高16位
逻辑 and $s1, $s2, $s3 $s1 = $s2 & $s3 三个寄存器操作数
or $s1, $s2, $s3 $s1 = $s2 | $s3 三个寄存器操作数
或非 nor $s1, $s2, $s3 $s1 = ~($s2 | $s3) 三个寄存器操作数
立即数与 andi $s1, $s2, 20 $s1 = $s2 & 20 和常数按位与
立即数或 ori $s1, $s2, 20 $s1 = $s2 | 20 和常数按位或
逻辑左移 sll $s1, $s2, 10 $s1 = $s2 << 10 常数左移相应位
逻辑右移 srl $s1, $s2, 10 $s1 = $s2 >> 10 常数右移相应位
条件分支 等于时跳转 beq $s1, $s2, 25

if( $s1 == $s2 ) go to

PC + 4 +100

相等检测;

和PC相关的跳转

不等于时跳转 bne $s1, $s2, 25

if( $s1 != $s2 ) go to

PC + 4 +100

不相等检测;

和PC相关的跳转

小于时置位 slt $s1, $s2, $s3

if( $s2 < $s3 ) $s1 = 1;

else $s1 = 0

比较是否小于

无符号数比较

小于时置位

sltu $s1, $s2, $s3

if( $s2 < $s3 ) $s1 = 1;

else $s1 = 0

比较是否小于无符号数

无符号数比较

小于立即数时置位

slti $s1, $s2, 20

if( $s2 < 20 ) $s1 = 1;

else $s1 = 0

比较是否小于常数

无符号数比较

小于无符号立即数时置位

sltiu $s1, $s2, 20

if( $s2 < 20 ) $s1 = 1;

else $s1 = 0

比较是否小于无符号常数
无条件跳转 跳转 j 2500 go to 10000 跳转至目标地址
跳转至寄存器所指位置 jr $ra go to $ra

用于switch语句,

以及过程调用

跳转并链接 jal 2500

$ra =  PC + 4;

go to 10000

用于过程调用

*注意:三个寄存器操作数:有且只有3个操作数,且操作数只能从32个32bit寄存器中选取。

硬件设计三条基本原则:

1、简单源于规整(只有三个操作数)

2、越小越好(只有32个寄存器)

3、优秀的设计需要适宜的折中方案(R型-->I型,见2.3节)

2.1 计算机硬件的操作数

寄存器大小:MIPS体系结构中寄存器大小为32bit。

字:计算机中基本的访问单位,32bit。

MIPS体系中共有32个寄存器,是由于设计原则2:越小越好和受指令格式位数的限制。

*注意:MIPS也有64bit的版本MIPS-64,其具有32个64bit的寄存器。此处32bit指的是MIPS-32。

2.1.1 存储器操作数

地址:用于在存储器空间中指明某特定数据元素的位置的值。

数据传送指令:存储器和寄存器之间传送数据的指令。

数据传送指令又分为取数指令存数指令

取数(load)指令:存储器-->寄存器,

存数(store)指令:寄存器-->存储器,

按字节编址:存储器被划分成若干个单元,每个单元容量为1个字节(8bit),从0开始编号(地址)。MIPS是按字节编址的

按字编址:存储器被划分为若干个单元,每个单元容量为1个字(32bit),从0开始编号。

对齐限制:数据地址与存储器的自然边界对齐的要求。

大端编址:使用最左边的字节地址作为字地址。MIPS使用的是大端编址

小端编址:使用最右边的字节地址作为字地址。

大端存储:低字节放在高地址高字节放在低地址

小端存储:高字节放在高地址低字节放在低地址

例如:数据0X12345678在0X20000000地址上的存储方式:

地址    小端 大端
0X20000000 0X78    0X12
0X20000001 0X56 0X34
0X20000002  0X34 0X56
0X20000003 0X12 0X78

疑问:大端编址和大端存储相等吗?


下面介绍怎样计算存储器地址的偏移量

MIPS存/取一个字(32bit)时,存储器地址的偏移量为该字的字地址。由于MIPS采用的是大段编址,所以字地址 = 最左的字节地址。存储器的字节地址如图所示:

上图中第一个字的最左字节地址是0,第二个字的最左字节地址是4,第三个字的最左字节地址为8,以此类推,第n个字的最左字节地址为:

最左的字节地址 = (n-1)*4 (这个字的第一个字节地址)


例题: 存数/取数指令

变量h存放在$s2中,数组A的地址存放在$s3中,编译赋值语句:A[12] = h + A[8]。

答案:lw $t0 32($s3)

          add $t0 $t0 $s2

          sw $t0 48($s3)

数组A中第9个字(A[8])的实际偏移量为8*4,所以字地址为$s3+32。

数组A中第13个字(A[12])的实际偏移量为12*4,所以字地址为$s3+48。


寄存器溢出:将不常使用的变量(或稍后才使用的变量)存回到存储器中的过程叫寄存器溢出。

寄存器相比存储器的优点:访问时间短,吞吐率高,访问速度更快,功耗更少。所以要更高效率的利用寄存器。

2.1.2 常数或立即数操作数

在加减法指令中,常数必须先从存储器中取出再运算,如寄存器$s3加4:

lw $t0 addrconstant4($s1)   // $s1+addrconstant4是常数4的存储器地址

        add $s3, $s3, $t0

加立即数(addi)可以直接加常数,如addi $s3, $s3, 4。具有执行速度快,能耗较低的优点。

MIPS支持负常数,因此不需要减立即数的指令。

2.2 有符号数和无符号数

2.1 无符号数

无符号二进制数1011在MIPS字中的存放位置如下图所示,

最低有效位:在MIPS中最右边的一位。

最高有效位:在MIPS中最左边的一位。

MIPS字的数值范围为从0到-1(4 294 967 295)。

2.2 有符号数

有符号数有四种表示方法,分别是“二进制补码”、“符号和幅值”、“反码”和“偏移表示法”,现在最常用的二进制补码,下面分别介绍各种方法。

二进制补码

求二进制补码:

正数的二进制补码=本身;

负数的二进制补码=其相反数的二进制取反 + 1.

MIPS字的取值范围为~~0~~如下图所示,

缺点:最小的负数没有相应的正数与之对应。

优点:所有负数的最高有效位都是1。因此有符号数的最高有效位也叫作符号位。常被用来检测一个数是正数还是负数。

符号扩展:当需要将16位的有符号数取到为32位寄存器上时,将符号位以复制的方式填满新数的高16位。

*注意:无符号数只需要简单的填充0到数据左侧的剩余位。MIPS指令取半字和取字节就是按照有符号数的符号扩展法处理的。取无符号半字和取无符号字节是按照无符号数的扩展方法处理的。

符号和幅值

方法:增加一个独立的符号位,来区分正数和负数。

缺点:1、符号位放哪里不明确。

2、不能在计算时得到结果的符号,需要额为一步得到符号。

3、存在正零和负零。

反码

方法:按位取反。

优点:最小负数由对应的正数对应。

缺点:1、存在正零(0000)和负零(1111)。

2、需要额外的一步减去一个数来修正结果。

偏移表示法

偏移表示法是一种浮点数表示方法,最小负数用00...00表示,最大正数用11...11表示,0一般用10...00表示。后面在第三章详细介绍。

2.3 计算机中指令的表示

MIPS汇编语言需要转换成机器指令,机器指令全部由数字组成。几乎所有的指令都用到寄存器,所以需要将寄存器的名字映射成数字。

寄存器及其对应的编号

机器指令分为若干字段,MIPS字段格式有两种为R型和I型。

R型
指令 op rs rt rd shamt funct
位数 6位 5位 5位 5位 5位 6位
注释 操作符 第一个源操作数的寄存器 第一个源操作数的寄存器 目的寄存器 左移或右移中的位移量 功能码

下图表示MIPS指令及其对应的MIPS字段格式。

*注:在取指令时,R型只能表示之内的常数,因此扩展出了I型,可以表示之内的偏移量。

2.4 逻辑操作

左移:sll $t2, $s0, 4 # reg $t2 = reg $s0 << 4 bits

右移:srl $t2, $s0, 4 # reg $t2 = reg $s0 >> 4 bits

按位与:and $t0, $t1, $t2 # reg $t0 = reg $t1 & reg $t2

按位或:or $t0, $t1, $t2 # reg $t0 = reg $t1 | reg $t2

或非:nor $t0, $t1, $t2 # reg $t0 = ~(reg $t1 | reg $t2)  只有都为0时,才为1。A与0或非=A取反。

2.5 决策指令

2.5.1 条件分支

beq reg1, reg2, L1 # if reg1=reg2 执行L1

bne reg1, reg2, L1 # if reg1不等于reg2 执行L1

例题:编译指令 if(i==j) f=g+h; else f=g-h; f,g,h,i,j依次对应$s0到$s4.

答案:bne $s3, $s4, Else

            add $s0, $s1, $s2

            j Exit     #无条件跳转指令(称为jump,简称j)

            Else:sub $s0, $s1, $s2

            Exit: 

2.5.2 循环

例题:while循环

编译下列语句,i和k分别放在寄存器$s3和$s5中,数组save的基址放在寄存器$s6中。

while(save[i] == k)

i +=1;

答案:loop : sll $t0, $s3, 2  # reg $t0 = i*4 (左移两位实现),字节寻址

           add $t0, $t0, $s6      # reg $t0 add 基址得到save[i]的地址

           lw $t1, 0($t0)           # save[i] 的值保存到 reg $t1

           bne $t1, $s5, Exit    # if  i 不等于 K,执行Exit

           addi $s3, $s3, 1      # else 执行 i = i + 1

           j loop                       # 然后继续循环

           Exit:

在for循环中需要判断索引便令是否小于某个值,在MIPS汇编语言中提供了小于则置位的指令。

有符号比较: slt $t0, $s0, $s1  # if  $s0 < $s1, $t0 == 1, else $t0 == 0

无符号比较: sltu $t0, $s0, $s1  # if  $s0 < $s1, $t0 == 1, else $t0 == 0

与立即数比较:slti $t0, $s0, 10  # if  $s0 < 10, $t0 == 1, else $t0 == 0

2.5.3 case/switch 语句

大多数程序数据语言中的case或switch语句,使程序员根据某个变量的值选择不同的分支,在MIPS汇编中,使用转移地址表实现分支转移。

转移地址表(或转移表):指包含不同指令序列地址的表,程序索引该表即可跳转到恰当的指令序列。程序需要跳转时,首先将转移表中适应的指令序列地址加载到寄存器中,然后使用寄存器中的地址进行跳转。

寄存器跳转指令:jr $s0  #无条件跳转的寄存器指定的地址

2.6 计算机硬件对过程的支持

过程:根据程序提供的参数,执行一定的任务的存储子程序。

参数:承担过程与其他程序、数据之间的接口。

过程运行的步骤:

1、程序 将参数放在过程可访问的位置;

2、程序 将控制转交给过程;

3、过程 获得过程所需要的资源;

4、过程 执行所需要的任务;

5、过程 将结果的值放在程序可访问的位置;

6、过程 将控制权还给程序,并返回到程序。

调用者:调用一个过程并提供必要参数的程序

被调用者:根据调用者提供的参数执行一系列存储指令,然后将控制权返回调用者的过程

程序计数器(PC):包含在程序中正在被执行指令地址的寄存器

$a0~$a3:用于传递参数的4个参数寄存器,用于步骤1中。

$v0~$v1:用于返回值得两个值寄存器,用于步骤5中。

$ra:用于返回程序的返回地址寄存器,用于步骤6中。

跳转和链接指令:跳转到某个地址的同时将下一条指令的地址保存到$ra中。

jal Procedureaddress # 跳转到过程,并将下一条指令的地址保存到$ra中,用于返回程序。

*注意:实际上保存到$ra的地址为PC+4,来表示下一条指令的地址

寄存器跳转:无条件跳转到寄存器所指定的地址。

jr $ra #在过程执行完后,跳转到$ra中保存的下一条指令的地址

根据上述概念过程运行的步骤又可以描述为:

1、调用者将参数存放在$a0~$a3中;

2、使用 jal X 跳转到过程X(被调用者);

3、被调用者执行运算,将结果放在$v0和$v1中;

4、使用 jr $ra 将控制返回给调用者。

2.6.1 过程使用更多的寄存器时

若过程需要使用多于4个参数寄存器和两个返回值寄存器时,需要在过程任务完成后,恢复多使用的寄存器之前的数据,因此需要在过程执行之前将寄存器中的数据放到存储器中,在过程执行之后再取回到寄存器中。

栈:被组织成先进后出的队列形式并用于寄存器换出的数据结构。

栈指针:指示栈中最近分配地址的值,它指示寄存器旧值存放的位置。在MIPS中,栈指针是寄存器$sp。

压栈:向栈中增加元素。

出栈:向栈中移除元素。


例题:求编译后的MIPS汇编代码,参数变量g、h、i、j对应参数寄存器$a0~$a3, f 对应寄存器$s0,同时使用了两个临时寄存器$t0和$t1。

int leaf_example (int g, int h, int i, int j)
{int f;f = ( g + h ) - ( i + j);return f;
}

答案:

##--------压栈---------addi $sp, $sp, -12sw $t1, 8($sp)sw $t0, 4($sp)sw $s0, 0($sp)##--------计算---------add $t0, $a0, $a1add $t1, $a2, $a3sub $s0, $t0, $t1##--------返回值---------add $v0 $s0, $zero##--------出栈---------lw $s0, 0($sp)lw $t0, 4($sp)lw $t1, 8($sp)##--------跳转---------jr $ra

*注意:1、栈指针总是指向栈顶,因此$sp需要减去12,从而保证sw的偏移量是正数。

2、栈增长是按照地址从高到底的顺序进行的,因此压栈时的偏移量从大到小。

3、字的首个字节地址在字的下方,因此$sp-12,而不是-8。

4、栈是先进后出的队列,因此出栈的顺序是$s0,$t0,$t1。

$t0~t9:10个临时寄存器,在调用过程中不必被调用者保存。

$s0~$s7:8个保留寄存器,在调用过程中必须被保存。

2.6.2 嵌套

叶过程:不调用其他过程的过程。

非叶过程属于嵌套,会出现以下问题:

例如:主程序将参数3存入到 $a0,然后使用jal A 调用过程A,过程A通过jal B 调用过程B,参数为7,同样存入到 $a0 中。由于A尚未结束任务,所以寄存器$a0的使用上存在冲突。同理,寄存器$ra保存的返回地址上也存在冲突

解决方法:将所有必须保留的寄存器压栈。

1、调用者将所有调用后还需要的参数寄存器($a0~$a3)或临时寄存器($t0~$t9)压栈;

2、被调用者将$ra和被调用者使用的保存寄存器($s0~$s7)压栈;

3、栈指针$sp随着栈中寄存器个数调整;

4、 返回时,寄存器会从存储器中恢复,栈指针也随着重新调整。


例题:求编译后的MIPS代码,参数n放入到$a0中。

int fact (int n)
{if(n<1) return(1);else return(n*fact(n-1));
}

答案:

fact:##---------压栈-------------addi $sp, $sp, -8sw $ra, 4($sp)sw $a0, 0($sp)##---------条件判断-------------stli $t0, $a0, 1beq $t0, $zero, L1##---------保存-------------addi $v0, $zero, 1##---------出栈-------------addi $sp, $sp, 8            ##由于$ra,$a0没有发生变化,所以不需要出栈##---------返回-------------jr $ra
L1:##---------重新赋值-------------addi $a0, $a0, -1jal fact##---------出栈-------------lw $a0, 0($sp)lw $ra, 4($sp)addi $sp, $sp, 8##---------保存-------------mul $v0, $a0, $v0##---------返回-------------jr $ra

下面总结了一般情况下过程调用使,那些寄存器需要保留或不需要保留:

过程调用时,保留和不保留的内容

*注意:上述例子中需要参数n重新赋值以前的值,所以n需要保留,即$a0要压栈。

2.6.3 在栈中为新数据分配空间

栈还需要存储过程的局部变量,但是这些变量不适用寄存器,例如局部的数组和结构体

过程帧(或活动记录):栈中包含过程所保存的寄存器以及局部变量的片段。

帧指针($fp):指向过程帧第一个字。

过程调用之前(a)、之中(b)、之后(c)栈的分配情况

*注意:若参数多于4个时,MIPS将额外的参数放在栈中指针上方(图中应该是下方吧?),过程从寄存器$a0~$a3中获得前4个参数,通过帧指针在内存中寻址获得其余参数。

2.6.4 在堆中为新数据分配空间

C语言包括两种存储方式:动态的和静态的。

动态变量:位于过程中,当过程退出时失效。

静态变量:在进入和退出过程时始终存在。

在所有过程之外声明的C变量,以及声明时使用关键字static的变量都被视为静态的,其余变量都被视为动态的。

全局指针($gp):指向静态数据区的保留寄存器。

除了动态变量对过程是局部有效外,C程序员还需要在内存中为静态变量和动态数据结构提供空间。MIPS的内存分配如下图所示。

程序和数据的MIPS内存分配

代码段:UNIX目标文件中的段,包含源文件中例程对应的机器语言代码。

静态数据段:存储常量和其他静态变量的空间。

堆:动态数据在某一区域中朝着栈方向向上生长,该区域为堆。

*注意:全局指针$gp应设置为适当的地址以便于访问数据。上图中$gp初始化为,这样通过$gp的正负16位的偏移量可以访问从之间的内存空间。

C语言通过显示的函数调用在堆上分配和释放空间:

1、malloc( ) 在堆上分配空间并返回指向他的指针。

2、free( ) 释放指针指向的堆空间。

3、忘记释放空间会导致“内存泄露”,会逐渐耗尽内存以至于操作系统可能崩溃。

4、过早释放空间会导致“悬摆指针”,会造成指针指向程序不想访问的位置。

Java使用自动内存分配和无用单元回收机制来防止类似错误发生。

寄存器当过程调用时是否保存

2.7 表示字符串的方式

2.7.1  ASCII 码表示字符

计算机使用8bit的ASCII码表示字符,部分ASCII表如下图所示:

ASCII码表

*注意:所有大写字母和对应小写字母的差均为32,这样方便检查和切换大小写字母。

常用到的MIPS指令有:

取字节:lb $t0, 0($sp)

取无符号字节:lbu $t0, 0($sp)

存字节:sb $t0, 0($sp)

字符通常被组合为字符数目可变的字符串,表示一个字符串的方法有三种选择:

1、保留字符串的第一个位置用于给出字符串的长度;

2、附加一个带有字符串长度的变量(如在结构体中)。

3、字符串最后的位置用一个字符来标识其结尾,C语言用0(ASCII码中的null)的字节来结束字符串。例如“Cal”在C语言中使用4个字节来表示,用十进制表示分别为:67、97、108、0。


例题:编译一个字符串复制过程,数组x和y的基地址在$a0和$a1中,i在$s0中。

void strpy(char x[], char y[])
{int i;i = 0;while((x[i] = y[i]) != '\0')  // 字符串y复制到字符串xi += 1;
}

答案:

strcpy:##-----------压栈------------------addi $sp, $sp, -4sw $s0, 0($sp)##-----------初始化-----------------add $s0, $zer0, $zero // i = 0
L1:add $t0, $a0, $s0     // y[i]的地址lbu $t1, 0($t0)       // $t1 = y[i] add $t2, $a1, $s0     // x[i]的地址sb $t1, 0($t2)        // x[i] = $t1 = y[i], 此处i没有乘4,因为y是字节的数组而不是字的数组beq $t1, $zero, L2    // 字节为0时,字符串结束,退出循环addi $s0, $s0, 1      // i = i + 1j L1                  // go to L1
L2:##-----------出栈------------------lw $s0, 0($sp)addi $sp, $sp, 4##-----------返回------------------jr $ra 

2.7.2  Unicode 表示字符

Unicode是大多数人类语言中字母的通用编码,更具有包容性。Java对字符使用Unicode,它默认使用16bit来表示一个字符。常用到的MIPS指令有:

取半字:lh $t0, 0($sp)

取无符号半字:lhu $t0, 0($sp)

存半字:sh $t0, 0($sp)

2.8 MIPS 中 32 位立即数和寻址

2.8.1 32位立即数

常数通常是16bit的,有时需要32bit的常数时,必须把大的常数分解为若干小的常数,然后再合并到一个寄存器中,合并指令有读取立即数最高位、立即数或

读取立即数最高位:lui $t0, 255

将16bit的常数255,放在$t0的高16bit上,低16bit保持不变。255 = 0000 0000 1111 1111 ,$t0=0000 0000 1111 1111 0000 0000 0000 0000

立即数或:ori $s1, $s1, 61

将16bit的常数61与32位寄存器$s1相或,若$s1的低16bit为0,则新的$s1低16bit为61,高16bit不变。

2.8.2 分支和跳转中的寻址

跳转指令寻址是最简单寻址方式,其MIPS指令格式如下:

j  10000 // go to location 1000

J型MIPS指令格式

跳转指令的操作码为2,跳转地址为10000,地址最大为 。

条件分支通常出现在循环或if语句中,例如

beq $s0, $s1, Exit 

I型MIPS指令格式

等于时跳转指令的操作码为5,Exit为指定分支地址,其不能大于,但是此地址长度可能会不够用。有一个可选办法是,指定一个加到分支地址上的寄存器,这样

分支地址 = 寄存器 + Exit

该寄存器选择为当前指令的地址(PC),这样我们可以转移离当前指令距离为个字的地方,同时几乎所有的循环和if语句都远远小于个字,分支地址几乎能全部是表示出来。这种寻址方式称为PC相对寻址

MIPS所有条件分支使用PC相对寻址;跳转链接指令使用J型格式来为过程调用提供长地址。

*注意:1、J型和I型MIPS指令格式的地址都表示字地址

2、当条件分支转移到很远时(超过16bit表示范围),该怎么办?

例如:beq $s1, $s2, L1   // L1属于远距离转移

解决方法: bne $s1, $s2, L2    

                                           j L1                        //使用无条件跳转L1

                                      L2:

2.8.3 MIPS寻址模式总结

寻址模式:根据对操作数和/或地址使用不同加以区分的多种寻址方式中的一种。

1、立即数寻址:操作数是位于指令自身中的常数。

2、寄存器寻址:操作数是寄存器。

3、基址寻址或偏移寻址:操作数在内存中,其地址是指令中基址寄存器和常数的和。

4、PC相对寻址:地址是PC和指令中常数的和。

5、伪直接寻址:跳转地址由指令中26位字段和PC高位相连而成。

2.8.4 机器语言解码

机器语言恢复到汇编语言的步骤如下:

1、恢复到二进制,找到操作码;

2、确定指令格式或指令类型;

3、根据格式完成解码。


根据操作数(31:26)找指令类型或R型

根据功能码(5:0)找R型的指令类型

MIPS指令格式

2.9 翻译并执行程序

从C语言转换为可执行程序的四个步骤如下:

2.10 ARMv7(32位)指令集

ARM与MIPS具有许多相似性,两者的主要区别是MIPS有更多的寄存器,ARM有更多地寻址模式。

ARM和MIPS指令集的相似性

MIPS与RAM在算数逻辑和数据传输指令方面具有相似的核心指令集

2.10.1 寻址模式

MIPS有三种寻址方式(立即数、寄存器、PC相对寻址),ARM有9种寻址方式,如下图所示:

数据寻址模式总结​​​​

 2.10.2 比较和条件分支

MIPS使用寄存器中的值来决定条件分支是否执行;

ARM使用4bit条件码来决定条件分支是否执行,4个条件码是:负值、零、进位和溢出。

2.10.3 ARM 特色

指令格式:

1、 ARM每条指令的4bit条件执行字段不同;

2、 ARM只有16个寄存器,所有具有较小的寄存器字段。

ARM和MIPS的指令格式

MISP中没有的ARM算数/逻辑指令:

此外,ARM还对寄存器组的操作码提供了指令支持,这些指令叫做块加载和存储

2.11 ARMv8(64位)指令集

v8删除了一些v7中不常用的特性:

v8增加了一些MIPS中有用的特性:

相对于v7,v8更像MIPS。ARMv7和ARMv8主要相同点仅仅是名字。

2.12 x86指令集

2.12.1 x86寄存器和数据寻址模式

80386寄存器组

两个操作数的算数、逻辑和数据传输指令的指令格式:

*注意:1、算数和逻辑指令中一个操作数必须既是源操作数有是目标操作数。

2、一个操作数可以再存储器中。

x86寻址模式和如何使用MIPS指令集来达到相同的效果如下图所示:

2.12.2 x86 整数操作

一些典型的x86操作

2.12.3 x86 总结

x86比ARM和MIPS的计算机更难制造,但是巨大的市场使得AMD和Intel投入更多的资源来克服额外的复杂性。

2.13 谬误与陷阱

谬误1:更强大的指令意味着更高的性能。

谬误2:使用汇编语言编程来获得更高的性能。

现在编译器产生的代码和手工编写的代码在性能上的差距几乎很小,而且汇编程序员需要深刻理解计算机体系结构概念。

汇编语言编写的缺点:需要更多的时间编码和调试,可移植性差,难于维护。

谬误3:商用计算机二进制兼容的重要性意味着成功的指令集不需要改变。

陷阱1:忘记在字节寻址的机器中,连续的字地址相差不是1。

陷阱2:在自动变量的定义过程外,使用指针指向该变量。

第二章 指令:计算机的语言相关推荐

  1. 关于c语言的基本知识,第二章_关于C语言的基本知识.ppt

    第二章_关于C语言的基本知识.ppt 函数 函数说明 例2.3 分析下面的运行结果. main() { printf("\"123\"\\\"456\" ...

  2. python语言程序设计2019版第二章课后答案-python语言程序设计基础课后答案第二章...

    python语言程序设计基础课后答案第二章 以下合法的用户自定义标识符是____________. 导入模块或者模块中的元素要使用关键字________ . 下列哪个函数是用来控制画笔的尺寸的____ ...

  3. python语言程序设计2019版第二章课后答案-python语言程序设计基础(嵩天)第二章课后习题...

    **第二学期第一周学习总结 一. 本周学习内容总结 一维数组,了解了一维数组的定义(定义一个数组,需要明确数组变量名,数组元素的类型和数组大小,即数组中元素的数量) 一维数组定义的一般形式为:类型名, ...

  4. 计算机原理简明教程第二章,《计算机原理简明教程》习题答案[参考].doc

    <计算机原理简明教程>习题参考答案 第一章习题答案 1.1 答:是1946年在美国宾夕法尼亚大学诞生,称为ENIAC. 特点是由1800个电子管和1500个继电器组成,重30吨:功耗150 ...

  5. 计算机组成原理第二章数据,计算机组成原理第二章数据在计算机中的表示

    计算机组成原理第二章数据在计算机中的表示 (91页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 14.90 积分 第二章 数据在计算机中的表示 n 概述 ...

  6. 计算机组成与设计:指令-计算机的语言

    2.1 引言 计算机语言中的基本单词成为指令,一台计算机的全部指令成为该计算机的指令集. 不同的指令集具有相似性,一方面是因为所有计算机都是基于基本原理相似的硬件技术所构建:另一方面所有计算机都必须提 ...

  7. c语言程序设计第二章的答案,C语言程序设计第二章作业参考答案

    C语言程序设计第二章作业参考 <C语言程序设计>第2章作业 布置日期:2017-10-23 截止日期:2017-11-3 一.单选题(每小题4分,共100分) 1.以下说法中正确的是___ ...

  8. 计算机组成原理第二章数据,计算机组成原理第二章数据表示(含答案)

    null 第二章数据表示 2.1 机器数及特点随堂测验 1.设计算机字长8位,设x = -5, [x]补为( ) (单选) A.FBH B.FDH C.FAH D.05H 2.系列关于补码机器数的描述 ...

  9. 计算机组成与结构第二章ppt,计算机组成原理(华科版)第二章 运算方法与运算器.ppt...

    文档介绍: 第二章运算方法与运算器 2.1 数据信息的表示方法 2.1.1数值数据的表示 淘在盛纬娃消镶勉桌乡利亚钦沙隐酋谴牲斗丙茸乔泛戊篡汽栽辫滔矮空芥计算机组成原理(华科版)第二章运算方法与运算器 ...

  10. 计算机组成原理第二章测试题,计算机组成原理第二章习题答案.doc

    计算机组成原理第二章习题答案 第2章?习题及解答 2-2?? 将下列十进制表示成二进制浮点规格化的数(尾数取12位,包括一位符号位:阶取4位,包括一位符号位),并写出它的原码.反码.补码三和阶移尾补四 ...

最新文章

  1. org.springframework.beans.factory.BeanCreationException 解决异常错误
  2. java string 后几位_java中String占几个位元组
  3. 如何使用图形界面Webmin管理linux服务器
  4. 人脸识别方法个人见解
  5. Flask-RESTful 快速入门
  6. 计算机地址栏搜索不了网,我的电脑地址栏不见了怎么办 地址栏不见了如何解决...
  7. jquery $.ajax post php获取不到_经典的jQuery实现页面公共部分方法,附代码
  8. 数据可视化(3)--Google Charts
  9. Android TextureView简易教程
  10. 在Mac下连接阿里云服务器
  11. Atitit.电脑图片与拍摄图片的分别
  12. python实现简单银行管理系统
  13. 面试时,如何回答关于“缺点”的问题——大学生求职七大昏招衍生系列(2)
  14. android高仿微信的图片查看
  15. matlab 卡丹 公式,卡丹公式是什么?请写出来,并用例题加以解释,
  16. 【报告分享】2021小红书投放运营指南书-小红书(附下载)
  17. 湖北民院OJ 最少美元付款
  18. Abaqus安装CAE报错Regview解决方法
  19. shell脚本之AWK-AWK的变量和AWK运算符
  20. android apk编译打包过程

热门文章

  1. python植物大战僵尸 豆约翰_python植物大战僵尸十四之采集太阳(太阳不是同时产生)...
  2. Python之选择结构(案例1:快递价格计算系统)
  3. The type of the expression must be an array type but it resolved to ListObj
  4. android获取电话通话记录,Android获取手机通话记录
  5. 购买namesilo域名可以用微信支付了
  6. mysql schemata_mysql8 参考手册-INFORMATION_SCHEMA SCHEMATA表
  7. Request textDocument/codeAction failed.
  8. java 调用 fastreport,Winform中使用FastReport实现简单的自定义PDF导出
  9. hdmi接口和计算机连接,hdmi接口,教您hdmi接口怎么连接电视
  10. AI英雄 | 论人工智能与自由意志,请看尤瓦尔与李飞飞的这场“激辩”