【计算机组成与设计 硬件/软件接口-2】MIPS指令集架构

【计算机组成与设计 硬件/软件接口-2】MIPS指令集架构_第1张图片

指令:计算机的语言

引言

所谓指令集,指的就是计算机的全部指令,这章节将以MIPS指令集作为学习对象,如果是x86指令集,还请参考《深入理解计算机系统》。MIPS指令集在嵌入式芯片市场占有相当大的市场份额,应用在包括用户电子,网络/存储设备,相机,打印机等等。学习MIPS指令集,其实最终只需要掌握几张表就足够了,要能看懂学会当成API文档进行查阅。本章节并不会讲解太多指令怎么用,我们的关注点更多的落在如何应用MIPS指令进行计算机的设计。

文档下载地址:MIPS Green Sheet

【计算机组成与设计 硬件/软件接口-2】MIPS指令集架构_第2张图片
【计算机组成与设计 硬件/软件接口-2】MIPS指令集架构_第3张图片

计算机硬件的操作

所有的算术运算指令,格式都是十分规整,以add a, b, c 为例,其表示a = b + c,这种设计符合硬件简单性原则,即规范化的设计使得硬件实现简单,简单让高性能变得低成本。

计算机硬件的操作数

一般硬件中的操作数,存在于三个地方,在寄存器中,在内存中,还有就是直接包含在指令当中,直接包含在指令当中的操作数,我们把它叫做立即数。

寄存器操作数

注意:所有的算逻运算,涉及到的读写都是使用寄存器,并不直接使用内存。

对于32位的MIPS机来讲,有32个寄存器,每个寄存器有32位,编号为0~31,32位的数据成为word(字)。对汇编器来讲,为了方便阅读,分为$t0,$t1,…,$t9,作为临时变量存储;$s0,$s1,…,$s7,作为已存储变量存储。MIPS为何不使用更多的寄存器呢?大量的寄存器可能会使得时钟周期变长,因为电信号传输更远的距离必然花费更长的时间。设计者必须在更多寄存器和加快时钟周期之间进行权衡。这就是越小越快的设计原则。

内存操作数

内存用于存储一些当前并不经常使用、容量较大的数据,如数组、结构体、动态数据。内存操作辅助算逻运算,可以将操作数从内存load到寄存器,也可以将操作数从寄存器store到内存。MIPS32中,以8位组成每个byte;操作数取哪一个,由地址标识。此外,MIPS32中,words在内存中是对齐的,地址必须是4的倍数,采用大端方式进行编址。大端和小端的区别,其实已经在x86的学习中涉及。假设现在有数:0x00 00 30 39,下面是大端法和小端法的表示:
【计算机组成与设计 硬件/软件接口-2】MIPS指令集架构_第4张图片
对处理器而言,内存相较于寄存器访问速度要慢很多。

立即数操作数

对于比较小的立即数,我们可以直接将它放在指令里面访问,这样可以避免到内存中取数。可想而知,一个load指令,肯定要比取立即数,花费更多的时钟周期。如果我们能够根据使用的频率,来定义常数,也是加速大概率事件的一个好方法。

有符号数和无符号数

这部分的内容过于基础了,这里简单点一下就可以。不过有关于数制之间的转换和甄别,是一定要掌握的。

无符号二进制整数

无符号整数,实质上就是把最高位当作数值位看待。

有符号二进制整数

无符号整数,实质上就是把最高位当作符号位看待。常见的一些数值范围应该要熟悉:C语言各种数据类型取值范围

符号扩展

符号扩展要做的事情,就是使用更多的位来表示一个数字,同时数值保持不变。在MIPS指令中,有一些指令会进行符号扩展:

  • addi:扩展立即数
  • lb,lh:扩展到取半字节/半字
  • beq,bne:扩展位移

对于无符号数扩展来说,我们仅需要补0;对于有符号数,我们仅需要补1。

计算机中指令的表示

指令和数据在计算机中的表示并没有什么差别,都是二进制编码表示。MIPS中有两种指令的格式。

R格式指令

所谓R格式指令,可以理解为指令只和寄存器打交道。R格式指令如下:
在这里插入图片描述

  • op:操作码
  • rs:第一个源寄存器编号
  • rt:第二个源寄存器编号
  • rd:目的寄存器编号
  • shamt:若有移位,表示移位位数
  • funct:功能码

例如,指令add $t0, $t1, $t2的指令格式为:
在这里插入图片描述
查表,对应翻译到二进制为:
在这里插入图片描述

I 格式指令

所谓I格式指令,可以理解为指令内包含了立即数(Immediate number)。I格式指令如下:

在这里插入图片描述

  • op:操作码
  • rt:目的或源寄存器编号
  • constant取值范围:–215 ~ 215 – 1

上面我们已经看到了,MIPS最终都把不同的指令归结为上面两种形式,不同的类型指令采用不同的解码方式,但是都是32位的统一指令长度,且尽可能保证指令格式相似,这体现了优秀的设计需要适宜的折中方案。

决策 | 循环

分支语句,其实就是在一个语句块的前后加上bne,beq等判断条件,条件成立则往下执行或跳转到某个label,继续执行相应的语句。而循环结构,其实就是在一定的条件内,让语句块形成一个闭环,反复执行这个语句块。这里面不讲太多,到最后综合举例的时候再看看就好了,其实和x86的语句结构是一样的。
在这个部分,我们还需要掌握的一个概念就是“基本块”,所谓基本块,指的是一个指令序列,这个指令序列内部没有跳出的指令,也没有被跳转到的指令。一些高级处理机能够加速基本块的执行。
最后提一点,在以字节寻址的MIPS机中,bne、beq机器指令的立即数(被设计者规定为字地址,非字节地址),都要乘上4才能得到最终的地址。

过程调用(计算机硬件对过程的支持)

ISA层面上的过程调用还是值得我们留意的,对MIPS来说,调用过程的步骤,和其他ISA并无太大差别:

  • 将参数放在过程可以访问的寄存器里
  • 将控制权转移给过程
  • 获得过程所需要的存储资源
  • 执行过程的操作
  • 过程将结果值放在调用过程可以访问到的寄存器
  • 将控制权返回到调用点

对于MIPS32来说,一些寄存器的用途如下:

  • $a0 – $a3: 传递参数
  • $v0, $v1: 返回结果值
  • $t0 – $t9: 临时寄存器,可以被调用者改写
  • $s0 – $s7: 保存参数,必须被调用者保存和恢复
  • $gp: 静态数据的全局指针寄存器
  • $sp: 堆栈指针寄存器
  • $fp: 帧指针寄存器-保存过程帧的第一个字
  • $ra: 返回地址寄存器

过程的调用一般用到指令:

  • jal:调用过程,跳转和链接
    这里注意 jal 和普通的 j 还是不同的,j只是简单地跳转到某地址执行指令,但是jal还附带了保存PC下条指令地址到$ra等操作
  • jr:过程返回,寄存器跳转

过程调用中一个比较有意思的例子是嵌套调用,要实现嵌套调用,一定得用到栈这种结构。举斐波那契数的计算如下:
斐波那契的递推公式是:f(n) = f(n-1) + f(n-2),初始f(0) = 1,f(1) = 1,规定n ≥ 2
其MIPS的汇编代码为:

fact:
addi $sp, $sp, -8     # 栈中开辟8字节空间
sw   $ra, 4($sp)      # 前4个字节保存返回地址
sw   $a0, 0($sp)      # 后4个字节保存过程参数,这里就是n
slti $t0, $a0, 1      # 测试一下是否到达了边界
beq  $t0, $zero, L1   # 还没到边界,跳转L1,继续递归
addi $v0, $zero, 1    # 若到边界,返回1
addi $sp, $sp, 8      # 出栈
jr   $ra              # 返回上层调用
L1: 
addi $a0, $a0, -1     # 准备新的参数
jal  fact             # 更深一层调用
lw   $a0, 0($sp)      # 这里是调用出口,先取得该层的n    
lw   $ra, 4($sp)      # 再取得该层的将来的返回地址
addi $sp, $sp, 8      # 出栈    
mul  $v0, $a0, $v0    # 将n和递归过程得到的结果相乘    
jr   $ra              # 返回上层调用

了解计算机硬件对过程的支持,还需要了解一下简单的内存布局示意:

  • 栈数据存储:
    【计算机组成与设计 硬件/软件接口-2】MIPS指令集架构_第5张图片
  • 内存宏观布局:
    【计算机组成与设计 硬件/软件接口-2】MIPS指令集架构_第6张图片

MIPS中的32位立即数和寻址模式

32位立即数

32位立即数用的比较少,毕竟大部分常数都比较小。MIPS给我们提供了一些指令可供操作。
构造一个32位立即数分两步,一是构造高16位,二是构造低16位:
lui $s0, 61
在这里插入图片描述
ori $s0, $s0, 2304
在这里插入图片描述

寻址模式
  • 立即数寻址:操作数是位于指令自身中的常数
  • 寄存器寻址:操作数是寄存器
  • 基址寻址(偏移寻址):操作数在内存中,其地址是指令基址寄存器和常数的和
  • PC相对寻址:地址是PC和指令中常数的和
  • 伪直接寻址:跳转地址由指令中26位字段和PC高位相连而成

【计算机组成与设计 硬件/软件接口-2】MIPS指令集架构_第7张图片

程序是怎么在机器上执行的

这个问题是很经典的问题,对一个简单Hello World程序在机器上的执行过程进行探索,我们能够漫游整个计算机系统。一般来说,现代计算机系统上,程序的执行流程是:
在这里插入图片描述
前面关于预处理和编译成asm就不用多说了,我们关注一下目标模块如何生成:
首先,一个单独的.o文件包含了本模块的基本信息,一般包含:

  • 目标文件头:描述目标文件其他部分的大小和位置
  • 正文段:翻译后的指令,包含机器语言代码
  • 静态数据段:包含在程序生命周期内分配的数据
  • 重定位信息,标记了一些程序加载进内存时依赖于绝对地址的指令和数据
  • 符号表,全局定义和外部引用
  • 调试信息:用于关联源文件

一个.o文件单打独斗行不通,需要其他的.o模块进行链接,才可以构造出一个可执行程序,例如输出就还需要用到printf.o文件,链接一般分两个阶段,即符号解析和重定位,这个阶段还涉及到合并相同内存段,虚拟内存空间映射等操作。

构造出来的可执行文件是存在于磁盘上的,我们需要加载它才能运行,加载的一般步骤如下;

  • 读取可执行文件头来确定正文段和数据段的大小
  • 为正文和数据创建一个足够大的地址空间
  • 把指令和初始数据拷贝到内存或者设置页表项,使它们可用
  • 把主程序的参数复制到栈顶
  • 初始化寄存器(包括堆栈指针 $ sp, 帧指针 $ fp, 全局指针$gp )
  • 跳转到启动进程
    复制参数到寄存器并调用主函数main
    主函数返回时,通过系统调用exit终止程序

以上就是程序运行的一次简单漫游。这里我们还要提点一下Java程序和JVM,实在太重要了。
下图展示了Java翻译和运行步骤:
【计算机组成与设计 硬件/软件接口-2】MIPS指令集架构_第8张图片
Java程序首先被编译成Java字节码指令集,JVM执对Java字节码文件进行解释,解释的优势就移植性强,从手机到网络浏览器,都有JVM的身影,劣势就是性能较差,与C程序相比存在10倍的性能差异。
为了保持可移植性,同时提升性能,开发Java下一阶段的目标是实现程序执行的同时可以翻译,叫JIT(Java即时编译器),JIT能够在运行Java时选择性地把一些方法编译成宿主机上地本地机器语言。

MIPS / ARM / x86 架构(了解)

之所以了解这些架构,主要还是为了拓宽一下视野(当然,某年腾讯的面试也问到了这些架构相关的话题)
【计算机组成与设计 硬件/软件接口-2】MIPS指令集架构_第9张图片
ARM、 MIPS 、X86三大架构对比

MIPS汇编的一些例子

  1. MIPS实现strcpy:
strcpy:
addi $sp, $sp, -4      # adjust stack for 1 item    
sw   $s0, 0($sp)       # save $s0    
add  $s0, $zero, $zero # i = 0
L1: 
add  $t1, $s0, $a1     # addr of y[i] in $t1    
lbu  $t2, 0($t1)       # $t2 = y[i]    
add  $t3, $s0, $a0     # addr of x[i] in $t3    
sb   $t2, 0($t3)       # x[i] = y[i]    
beq  $t2, $zero, L2    # exit loop if y[i] == 0      
addi $s0, $s0, 1       # i = i + 1   
j    L1                # next iteration of loop
L2: 
lw   $s0, 0($sp)       # restore saved $s0    
addi $sp, $sp, 4       # pop 1 item from stack    
jr   $ra               # and return

其他补充

指令集总结:

  • 真实MIPS指令
MIPS指令 名称 格式
add R
sub R
加立即数 addi I
取字 lw I
存字 sw I
取半字 lh I
取无符号半字 lhu I
存半字 sh I
取字节 lb I
取无符号字节 lbu I
存字节 sb I
取链接字 ll I
存条件字 sc I
取立即数高位 lui I
and R
or R
或非 nor R
与立即数 andi I
或立即数 ori I
逻辑左移 sll R
逻辑右移 srl R
相等跳转 beq I
不相等跳转 bne I
小于置位 slt R
小于立即数置位 slti I
小于无符号立即数置位 sltiu I
跳转 j J
跳转至寄存器指定位置 jr R
跳转和链接 jal J
  • 伪指令
MIPS伪指令 名称 格式
移位 move R
mult R
乘立即数 multi I
取立即数 li I
小于跳转 blt I
小于等于跳转 ble I
大于跳转 bgt I
大于等于跳转 bge I

指令格式总结:
【计算机组成与设计 硬件/软件接口-2】MIPS指令集架构_第10张图片

你可能感兴趣的:(计算机组成原理)