赞
踩
32个寄存器
寄存器编号 | 助记符 | 用法 |
---|---|---|
0 | $zero | 值恒为0 |
1 | $at | 被汇编器保存用于处理大的常数 |
2-3 | $v0 - $v1 | 用于过程调用时返回结果 |
4-7 | $a0 - $a3 | 用于过程调用时传递参数 |
8-15 | $t0 - $t7 | 临时寄存器 |
16-23 | $s0 - $s7 | 保存寄存器 |
24-25 | $t8 - $t9 | 临时寄存器 |
26-27 | $k0 - $k1 | 通常被中断或异常处理程序使用,用来保存一些系统参数 |
28 | $gp | 全局指针寄存器 |
29 | $sp | 堆栈指针寄存器 |
30 | $fp | 帧指针寄存器 |
31 | $ra | 返回地址寄存器 |
在MIPS体系结构中,寄存器的大小为32位(也称为1个字)。
在MIPS中,只能对存放在寄存器中的数据执行算术操作。
寄存器个数限制为32的理由可以表示为硬件设计三条基本原则中的第二条:越小越快。
1.大量的寄存器可能会使时钟周期变长,因为电信号传输更远的距离必然花费更长的时间。
2.受指令格式位数的限制。
许多程序的变量个数要远多于计算机的寄存器个数。因此,编译器会尽量将最常用的变量保持在寄存器中,而将其他的变量放在存储器中。
MIPS采用的是大端、按字节编址的方式。
存储器就是一个很大的下标从0开始的一维数组,地址就相当于数组的下标。
由于load和store的指令中的地址是二进制,因此作为主存的DRAM的容量使用二进制表示,而非十进制。
类别 | 指令 | 实例 | 含义 | 注释 |
---|---|---|---|---|
算术运算 | 加法 | add $s1, s 2 , s2 , s2,s3 | $s1= $s2+ $s3 | |
算术运费 | 减法 | sub $s1, $s2, $s3 | $s1= $s2- $s3 | |
算术运算 | 立即数加法 | addi $s1, $s2 ,20 | $s1= $s2+20 | |
逻辑运算 | 按位与 | and $s1, s 2 , s2 , s2,s3 | $s1= $s2 & $s3 | |
逻辑运算 | 按位或 | or $s1, s 2 , s2 , s2,s3 | $s1= $s2 | $s3 | |
逻辑运算 | 或非 | nor $s1, s 2 , s2 , s2,s3 | $s1= ~( $s2 | $s3) | |
逻辑运算 | 立即数与 | andi $s1, $s2, 20 | $s1= $s2 & 20 | |
逻辑运算 | 立即数或 | ori $s1, $s2 ,20 | $s1= $s2 | 20 | |
逻辑运算 | 逻辑左移 | sll $s1, $s2,10 | s 1 = s1= s1=s2<<10 | |
逻辑运算 | 逻辑右移 | srl $s1, $s2,10 | s 1 = s1= s1=s2>>10 | |
数据传输 | 取字 | lw $s1,20( $s2) | $s1=Memory[ $s2+20] | |
数据传输 | 存字 | sw $s1,20( $s2) | Memory[ $s2+20]= $s1 | |
数据传输 | 取立即数的高位 | lui $s1,20 | $s1=20*216 | 将16位立即数常量放到目的寄存器的高16位,低16位用0填充 |
条件分支 | 相等时跳转 | beq $s1, $s2,Label | if( $s1== $s2) go to PC+4+4*Label | Label是字地址,对应字节地址要*4 |
条件分支 | 不等时跳转 | bne $s1, $s2,Label | if( $s1!= $s2) go to PC+4+4*Label | |
条件分支 | 小于时置位 | slt $s1, $s2, $s3 | if($s2< $s3) $s1=1;else $s1=0 | |
无条件跳转 | 跳转 | j Label | go to Label*4 | |
无条件跳转 | 跳转至寄存器所指位置 | jr $ra | go to $ra | |
无条件跳转 | 跳转并链接 | jal Label | $ra=PC+4;go to Label*4 |
计算机为了保持三操作数的格式,引入或非 NOR来取代按位取反 NOT操作(该操作仅有一个操作数)。
如果一个操作数是0,那么对于另一个操作数而言,结果就等价于NOT: A NOR 0=NOT(A OR 0)=NOT(A)。
所有操作数类型都是寄存器操作数。
包含 add,sub,and,or,nor,slt,jr指令
32位的MIPS指令分为6个字段
op | rs | rt | rd | shamt | funct |
---|---|---|---|---|---|
6位 | 5位 | 5位 | 5位 | 5位 | 6位 |
op: operation code,操作码
rs: register source 源操作数寄存器1
rt: s后面是t,源操作数寄存器2
rd: register destination,目的操作数寄存器
shamt: shift amount,移位量
funct:function code 功能码
R型指令的操作码6位都是0,由功能码进一步确定执行什么操作。
寄存器寻址
两个寄存器操作数加上一个立即数格式的指令。
包含addi,ori,lui指令
op | rs | rt | constant |
---|---|---|---|
6位 | 5位 | 5位 | 16位 |
op: operation code,操作码
rs: register source 源操作数寄存器
rt: 由于rd被合并,rt现在成了目的操作数寄存器
constant :立即数
立即数寻址
两个寄存器操作数加上一个立即数格式的指令。
包含lw,sw指令
op | rs | rt | address |
---|---|---|---|
6位 | 5位 | 5位 | 16位 |
op: operation code,操作码
rs: register source 源操作数寄存器
rt: 由于rd被合并,rt现在成了目的操作数寄存器
address: 相对于基址的地址偏移量
基址偏移寻址:
将基址寄存器的值和偏移量相加得到地址
两个寄存器操作数加上一个标签的指令。
包含beq,bne指令
op | rs | rt | address |
---|---|---|---|
6位 | 5位 | 5位 | 16位 |
op: operation code,操作码
rs: register source 源操作数寄存器
rt: 由于rd被合并,rt现在成了目的操作数寄存器
address: 分支标签的目标地址,标签翻译机器语言其实是个整数,告诉计算机从当前指令的地址出发,到达分支目标地址的距离是多少,即PC相对地址(可正可负的偏移量)。
PC相对寻址
先将PC相对地址左移两位形成18位字节偏移量,再和PC+4中的字节地址相加,形成分支目标地址。
只包含操作码和目标地址(立即数)
包含j,jal
op | address |
---|---|
6位 | 26位 |
op:操作码
address:目标地址
伪直接寻址
直接寻址是指指令中直接给出32位地址,但J型指令地址字段只有26位。
因此执行J型指令时,先把26位字地址左移两位形成28位字节地址,再和PC的高四位拼接成32位地址。
PC相对寻址以PC+4为基准,加上一个可正可负的16位补码字地址,寻址范围为
(PC+4)-217~(PC+4)+217-4 大约是分支前后各128KB
伪直接寻址用PC中当前指令地址的高四位拼接指令中的26位字地址,寻址范围为
和PC高四位相同的一切地址,即一个256MB的地址块
要分支到更远距离,可以将beq/bne取反,下接一条可能绕过的jr指令
bne $s0, $s1,exit
j L1
exit:
这样寻址范围就变成了和PC高四位相同的一切地址,即一个256MB的地址块。
要跳转到更远的距离
先将32位地址装载到一个临时寄存器,再用jr指令。
lui $t0, 高16位
ori $to, $t0,低16位
过程是根据提供的参数执行一定任务的存储的子程序。是软件中实现抽象的一种方法。
过程的执行过程
过程运行中,程序必须遵循以下6个步骤:
1.将参数放在过程可以访问的位置。($a0- $a3 四个参数寄存器)
2.将控制转交给过程。
3.获得过程所需的存储资源。
4.执行需要的任务。
5.将结果的值放在调用程序可以访问的位置。( $v0- $v1两个返回值寄存器)
6.将控制返回初始点,因为一个过程可能有一个程序的多个点调用。(用于返回起始点的返回地址寄存器 $ra)
MIPS还提供了两条指令——jal和jr。
调用程序(调用者)将参数值放在**($a0- $a3), 然后使用 jal X跳转到过程X** (被调用者)。被调用者执行运算,将结果放在** $v0- $v1**,然后使用jr $ra指令将控制返回调用者。
jal实际将PC+4保存在寄存器 $ra中,从而将链接指向下一条指令,为过程返回做好准备。
PC(程序计数器):包含在程序中正在被执行指令地址的寄存器。
叶过程:不调用其他过程的的过程。
假如主程序使用所有的8个保存寄存器,在主程序过程中调用了过程A,过程A需要使用3个保存寄存器,此时保存寄存器的数量已经不足供过程A使用。因此,我们需要先把主程序中8个保存寄存器的值保存到存储器中,此时过程A可以使用保存寄存器,待过程A结束后,再将存储器中保存的值恢复到8个保存寄存中。
这种换出寄存器的最理想的数据结构是栈——一种后进先出的队列。
栈指针:指向栈中最新分配的地址。
MIPS为栈指针准备了栈指针寄存器——$sp.
向栈中放入数据称为压栈,移除数据称为出栈。
栈中包含过程所保存的寄存器和局部变量的片段成为过程帧或活动记录。
过程调用之前、之中、之后栈的状态:
帧指针指向该帧的第一个字。
栈指针指向栈顶。
在程序运行期间,栈指针可能会改变,所以使用固定的帧指针引用变量会更简单
在所有过程之外声明的C变量,以及声明时使用关键字static的变量都被视作静态的,其余的变量都被视作动态的。
为了简化静态数据的访问,MIPS保留了全局指针寄存器$gp, $gp指向静态数据区的适当位置便于访问
数据。
程序在内存中分为5段,地址从低到高分别为:
1.保留段
2.正文段(代码段),保存指令。
3.静态数据段:存储常量和其它静态变量。例如数组这类在生命周期内具有固定长度的数据。
4.动态数据段(堆):存储链表这类在生命周期内增长或缩短的动态数据。堆由低地址向高地址生长。
5.栈:由高地址向低地址生长。
栈和堆此消彼长,实现了内存的高效利用。
编译器:将C程序转换成一种机器能理解的符号形式的汇编语言程序。
汇编器:
1.将伪指令转换成功能等价的机器语言指令
2.将汇编语言程序转换成目标文件,它包括机器语言指令、数据和指令正确放入内存所需要的信息。
伪指令是汇编语言指令的一个变种,通常被看作一条汇编指令。
常见的伪指令包括move、blt、bgt、ble、bge等。
伪指令使MIPS拥有比硬件所实现的更为丰富的汇编语言指令集。唯一的代价是保留了一个由汇编器使用的寄存器$at。
为了产生汇编语言程序中每条指令对应的二进制表示,汇编器必须处理所有标号对应的地址。汇编器将分支和数据传输指令中用到的标号都放入一个符号表中,这个表由标号和地址成对构成。
UNIX系统中的目标文件通常包含以下6个不同的部分:
1.目标文件头,描述目标文件其它部分的大小和位置。
2.代码段,包含机器语言代码。
3.静态数据段,包含在程序生命周期内分配的数据。
4.重定位信息:标记了一些在程序加载进内存时依赖于绝对地址的指令和数据。
5.符号表:包含未定义的剩余标记,如外部引用。
6.调试信息:包含一份说明目标模块如何编译的简明描述,这样调试器能够将机器指令关联到C源文件,并使数据结构也变得可读。
为什么单独编译和汇编每个过程?
避免因为任意一行代码的修改都要重新编译个汇编整个程序,特别是在定义上从未改变过的过程,是对计算资源的严重浪费。
这种方法需要一个新的系统程序,成为链接器。
链接器:也称链接编辑器,一个系统程序,把各个独立汇编的机器语言程序组合起来并且解决所有未定义的标记,最终生成可执行文件。
链接器的工作分三个步骤:
1.将代码和数据模块象征性地放入内存。
2.决定数据和指令标签地地址。
3.修补内部和外部引用
链接器使用每个目标模块中地重定位信息和符号表,来解析所有的未定义标签。
如果所有外部引用都解析完,链接器接着决定每个模块将要占用的内存位置。当链接器将一个模块放到内存中的时候,所有绝对引用,即与寄存器无关的内存地址必须重定位以反映它的真实地址。
可执行文件;一个具有目标文件格式的功能程序,不包含未解决的引用。它可以包含符号表和调试信息。
加载器:将可执行文件放入内存,装载执行。
在UNIX系统中,加载器按照如下步骤工作:
1.读取可执行文件头来确定代码段和数据段的大小。
2.为正文和数据创建一个足够大的空间。
3.将可执行文件中的指令和数据复制到内存中。
4.把主程序的参数复制到栈顶。
5.初始化机器寄存器,将栈指针指向第一个空位置。
6跳转到启动例程,它将参数复制到参数寄存器并且调用程序的main函数。当main函数返回时,启动历程通过系统调用exit终止程序。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。