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

在这里插入图片描述

指令:计算机的语言

引言

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

文档下载地址:MIPS Green Sheet

在这里插入图片描述
在这里插入图片描述

计算机硬件的操作

所有的算术运算指令,格式都是十分规整,以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,下面是大端法和小端法的表示:
在这里插入图片描述
对处理器而言,内存相较于寄存器访问速度要慢很多。

立即数操作数

对于比较小的立即数,我们可以直接将它放在指令里面访问,这样可以避免到内存中取数。可想而知,一个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              # 返回上层调用

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

  • 栈数据存储:
    栈中数据存储
  • 内存宏观布局:
    在这里插入图片描述

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

32位立即数

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

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

在这里插入图片描述

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

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

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

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

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

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

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

MIPS / ARM / x86 架构(了解)

之所以了解这些架构,主要还是为了拓宽一下视野(当然,某年腾讯的面试也问到了这些架构相关的话题)
在这里插入图片描述
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指令名称格式
addR
subR
加立即数addiI
取字lwI
存字swI
取半字lhI
取无符号半字lhuI
存半字shI
取字节lbI
取无符号字节lbuI
存字节sbI
取链接字llI
存条件字scI
取立即数高位luiI
andR
orR
或非norR
与立即数andiI
或立即数oriI
逻辑左移sllR
逻辑右移srlR
相等跳转beqI
不相等跳转bneI
小于置位sltR
小于立即数置位sltiI
小于无符号立即数置位sltiuI
跳转jJ
跳转至寄存器指定位置jrR
跳转和链接jalJ
  • 伪指令
MIPS伪指令名称格式
移位moveR
multR
乘立即数multiI
取立即数liI
小于跳转bltI
小于等于跳转bleI
大于跳转bgtI
大于等于跳转bgeI

指令格式总结:
在这里插入图片描述

  • 4
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值