⚠ 转载请注明出处:作者:ZobinHuang,更新日期:Dec.11 2021
本作品由 ZobinHuang 采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可,在进行使用或分享前请查看权限要求。若发现侵权行为,会采取法律手段维护作者正当合法权益,谢谢配合。
1. 关于指令集架构
我们首先要给 指令集架构 (Instruction Set Architecture) 下一个定义,有时它也被简称为 架构 (Architecture)。处理器是按照 指令 (Instruction) 来运行的,因此指令实际上就是计算机的语言,指令的集合被称为 指令集 (Instruction Set)。所有的运行在同一台计算机的程序运行的都是基于同一套指令集开发的。指令集有两种形式:机器语言 (Machine Language) 和 汇编语言 (Assembly Language)。为了让只能理解二进制的机器运行指令,指令集最终都需要被编码成 0/1 的二进制格式,这就是机器语言; 而对于人类来说,为了使得程序的可读性更强,作为程序员我们则更倾向于使用更加直观的汇编语言来编写和理解程序。
一种指令集架构并没有定义底层的具体硬件实现,比如 Intel 和 AMD 都基于 x86 架构来设计它们的芯片,它们底层的硬件设计是不同的,因此它们的芯片拥有不同的性能、价格和功耗。
我们在本文中将关注 MIPS 指令集架构,这是一种上个世纪八十年代在 Stanford University 被开发出来的架构。
2. Register Set
在 MIPS 寄存器中有如下的寄存器资源:
Name |
Number |
Use |
---|---|---|
$0 |
0 |
常数值 0 |
$at |
1 |
Assembler Temporary |
$v0-$v1 |
2-3 |
函数返回值 |
$a0-$a3 |
4-7 |
函数参数 |
$t0-$t7 |
8-15 |
临时变量 |
$s0-$s7 |
16-23 |
用于保存变量 |
$t8-$t9 |
24-25 |
临时变量 |
$k0-$k1 |
26-27 |
Operating System Temporaries |
$gp |
28 |
Global Pointer |
$sp |
29 |
Stack Pointer |
$fp |
30 |
Frame Pointer |
$ra |
31 |
函数返回地址 |
3. Machine Language
MIPS 是一种 RISC 架构,它的指令编码长度是恒定不变的。考虑最极端的情况,把所有的指令都编码称为相同的编码格式,这样一来底层硬件的设计可以变得更加简化,但是这对指令的灵活性提出了很高的限制。因此,MPIS 把指令编码格式分为了三类: Register-Type (R-Type), Instruction-Type (I-Type) 和 Jump-Type (J-Type),这三种类型的编码都不相同,MIPS 把它所有的指令都塞进了这三类编码格式中,可以认为是一种折衷的方式。
我们下面分别对上面提到的 MIPS 的三种指令编码格式进行分析。
3.1 R-Type
R-type 指令对三个寄存器 (i.e. 两个源寄存器,一个目的寄存器) 进行操作,其格式如上图所示,各个字段解释如下:
op
: 操作码 (opcode, operation code),R-Type 的 opcode 为 0;funct
: 用于决定 R-Type 的具体指令,如add
,sub
等;rs
: 源寄存器;rt
: 源寄存器;rd
: 目的寄存器;shamt
: 仅用于移位的指令,用于指定移位的位数
下面是 R-Type 指令的编码实例:
3.2 I-Type
I-Type 指令对两个寄存器和一个 16-bits 的立即数进行操作,其格式如上图所示,各个字段解释如下:
op
: 用于决定 I-Type 的具体指令,比如addi
,lw
等;rs
: 源操作数;rt
: 有时作为源寄存器 (e.g.sw
),有时作为目的寄存器 (e.g.lw
);imm
: 源立即数;
下面是 I-Type 指令的编码实例,注意到 rt
虽然在汇编语言中是第二个出现的寄存器,但是它在机器语言中被编码在了第一个寄存器的位置:
3.3 J-Type
J-Type 指令对一个 26-bits 的立即数进行操作,只有跳转指令会使用这种编码格式。其格式如上图所示。
4. MIPS Programming, Address Mode 和 Software Build
关于 MIPS 架构的编程部分的细节,详见 MIPS Programming, Address Modes & Build,后续有空我再继续进行整理。