计算机指令集与MIPS体系结构
一、引言
- 计算机语言:计算机通过指令集(instruction set)与程序员交互,指令是计算机语言的基本单词。
- 指令集形式:
- 汇编语言:程序员书写的助记符形式,便于人类理解。
- 机器语言:计算机识别的二进制形式。
- 研究方法:自顶向下,从汇编语言逐步深入到机器语言,揭示硬件实现原理。
- 后续内容:第3章将探讨算术运算硬件和浮点数表示。
二、指令集概述
- 定义:指令集是一个给定计算机体系结构所包含的全部指令集合。
- 特点:
- 不同机器语言类似,差异如同“方言”,核心操作一致。
- 指令集设计目标:便于硬件和编译器设计,优化性能,降低成本和功耗。
- MIPS指令集:
- 自20世纪80年代起,成为优秀指令集的代表。
- 与ARMv7、Intel x86、ARMv8等主流指令集对比,MIPS具有简洁性和规整性。
- 其他指令集:
- ARMv7:2011年产量超90亿片,最流行指令集。
- Intel x86:主导PC和云计算领域。
- ARMv8:扩展到64位地址,更接近MIPS设计。
- 设计原则(1947年,von Neumann):
- 设备简单性:指令集需简化硬件设计。
- 指令集应高效解决实际问题,提升处理速度。
三、存储程序概念
- 定义:指令和数据以数字形式存储于存储器中,奠定了现代计算机基础。
- 优势:
- 程序和数据统一存储,简化硬件和软件设计。
- 计算机可灵活切换功能(如从记账到文字编辑)。
- 支持编译器、编辑器等程序运行,增强通用性。
四、MIPS指令集详解
1. 操作数
- 寄存器:
- 32个32位寄存器(如
$s0-$s7
、$t0-$t9
、$zero
等)。 - 用于快速数据存取,算术运算仅对寄存器操作。
$zero
恒为0,$at
为汇编器保留。- 存储器:
- 通过数据传输指令(如
lw
、sw
)访问。 - 按字节编址,字地址间隔为4字节。
- 用于存储数据结构、数组及寄存器溢出数据。
2. 汇编语言指令
- 算术指令:
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)
:从内存$s2+20
加载字到$s1
。sw $s1, 20($s2)
:将$s1
存入内存$s2+20
。- 支持半字(
lh
、sh
)、字节(lb
、sb
)及无符号操作(lhu
、lbu
)。 - 逻辑指令:
- 移位:
sll
(逻辑左移)、srl
(逻辑右移)。 - 按位操作:
and
、or
、nor
、andi
、ori
。 nor
用于取反,andi
/ori
支持立即数。- 条件分支:
beq $s1, $s2, L1
:若$s1==$s2
,跳转到标签L1
。bne $s1, $s2, L1
:若$s1!=$s2
,跳转到标签L1
。- 无条件跳转:
j 2500
:跳转到目标地址。jr $ra
:跳转到寄存器$ra
指定地址。jal 2500
:跳转并链接,保存返回地址。
3. 指令格式
-
R 型指令 (Register Type):
- 格式:
opcode | rs | rt | rd | shamt | funct
(6 | 5 | 5 | 5 | 5 | 6 bits) - 特点: 主要用于寄存器之间的操作。指令中包含源寄存器(
rs
和rt
)和目标寄存器(rd
)的地址。shamt
字段用于移位指令,funct
字段与opcode
一起确定具体的操作。 - 例子:
add
,sub
,and
,or
,slt
(set on less than),sll
(shift left logical),srl
(shift right logical)。 -
I 型指令 (Immediate Type):
-
格式:
opcode | rs | rt | immediate
(6 | 5 | 5 | 16 bits) - 特点: 用于涉及立即数(直接编码在指令中的常数)的操作。指令中包含一个源寄存器(
rs
)、一个目标寄存器(rt
,有时也作为源)和一个 16 位的立即数。 - 应用:
- 算术/逻辑运算(带立即数):
addi
(add immediate),andi
,ori
。 - 数据传输(加载/存储):
lw
(load word),sw
(store word)。基地址在rs
中,偏移量是immediate
,数据在rt
中(对于lw
是目标,对于sw
是源)。 - 条件分支:
beq
(branch on equal),bne
(branch on not equal)。比较rs
和rt
的值,如果条件满足,则跳转到由immediate
计算出的地址。
- 算术/逻辑运算(带立即数):
-
J 型指令 (Jump Type):
-
格式:
opcode | target address
(6 | 26 bits) - 特点: 用于无条件跳转。指令中包含一个 26 位的目标地址字段。
- 例子:
j
(jump),jal
(jump and link)。jal
在跳转前会将返回地址(当前指令的下一条指令地址)保存到$ra
寄存器中,常用于函数调用。 - 设计原则:
- 简单源于规整:固定指令长度(32位),统一格式。
- 越小越快:限制寄存器数量(32个)以加速时钟周期。
- 格式:
4. 机器语言
- 定义:指令的二进制表示,称为机器码。
- 编码:
- 操作码(
op
):指明指令类型。 - 寄存器字段(
rs
、rt
、rd
):指定操作数。 - 功能码(
funct
):R型指令的特定操作。 - 地址/立即数字段:I型指令的偏移量或常数。
- 十六进制表示:便于人类阅读,每4位二进制对应1位十六进制。
五、计算机硬件操作
1. 算术运算
- 格式:
add a, b, c
(a = b + c
),固定3个操作数。 - 编译示例:
- C语句:
a = b + c; d = a - e;
- MIPS:
add $s1, $s2, $s3; sub $s4, $s1, $s5
- 复杂语句:
f = (g + h) - (i + j);
- MIPS:
add $t0, $s1, $s2; add $t1, $s3, $s4; sub $s0, $t0, $t1
- 设计原则:固定操作数简化硬件设计。
2. 存储器操作
- 寄存器 vs 存储器:
- 寄存器:快速访问,数量有限(32个)。
- 存储器:容量大,访问慢,存储数组/结构。
- 数据传输:
lw
:从存储器加载字到寄存器。sw
:从寄存器存储字到存储器。- 示例:
g = h + A[8];
→lw $t0, 32($s3); add $s1, $s2, $t0
- 字节编址:
- MIPS按字节编址,字地址为4的倍数(对齐限制)。
- 大端编址:字地址为最左边字节地址。
- 寄存器溢出:编译器通过
lw
/sw
将变量“溢出”到存储器。
3. 立即数操作
- 加立即数:
addi $s3, $s3, 4
($s3 += 4
)。 - 优势:避免从存储器加载常数,加速执行,降低功耗。
- 零寄存器:
$zero
恒为0,简化指令设计。
六、有符号数与无符号数
1. 数的表示
- 二进制:计算机以二进制位(bit)表示信息,0或1。
- 字:MIPS中32位为一字,最高有效位(MSB)为31位,最低有效位(LSB)为0位。
- 无符号数:
- 范围:0到2³²-1(4,294,967,295)。
- 示例:
1111...1111₂ = 4,294,967,295₁₀
。 - 有符号数(二进制补码):
- 范围:-2³¹到2³¹-1(-2,147,483,648到2,147,483,647)。
- 符号位:MSB为0表示正,1表示负。
- 示例:
1111...1100₂ = -4₁₀
。
2. 二进制补码
- 优点:
- 符号位直接判断正负,简化硬件实现。
- 避免正负零问题(相比符号和幅值表示法)。
- 求反:按位取反后加1(如2₁₀ → -2₁₀)。
- 符号扩展:将16位数扩展到32位,复制符号位到高位。
- 溢出:操作结果超出表示范围,符号位错误。
3. 其他表示法
- 反码:
- 负数为按位取反,正负零存在,需额外加法修正。
- 示例:最小负数
100...000₂ = -2,147,483,647₁₀
。 - 偏移表示法:
- 用于浮点数,最小负数为
00...000₂
,最大正数为11...111₂
。
七、逻辑操作
- 移位:
sll $t2, $s0, 4
:左移4位(乘以2⁴)。srl $t2, $s0, 4
:右移4位(除以2⁴)。- 按位操作:
and $t0, $t1, $t2
:按位与,用于掩码。or $t0, $t1, $t2
:按位或。nor $t0, $t1, $t3
:或非,单操作数取反($t3=0
)。- 立即数逻辑:
andi $t0, $t1, 20
:与常数按位与。ori $t0, $t1, 20
:与常数按位或。
八、决策与循环
1. 条件分支
- 指令:
beq $s1, $s2, L1
:相等则跳转。bne $s1, $s2, L1
:不相等则跳转。- 编译示例:
- C语句:
if (i == j) f = g + h; else f = g - h;
- MIPS:
asm bne $s3, $s4, Else add $s0, $s1, $s2 j Exit Else: sub $s0, $s1, $s2 Exit:
2. 循环
- 示例:
- C语句:
while (save[i] == k) i += 1;
- MIPS:
asm Loop: sll $t1, $s3, 2 add $t1, $t1, $s6 lw $t0, 0($t1) bne $t0, $s5, Exit addi $s3, $s3, 1 j Loop Exit:
- 基本块:无分支(除末尾)和分支目标(除开头)的指令序列。
3. 小于比较
- 指令:
slt $t0, $s3, $s4
:若$s3 < $s4
,$t0 = 1
,否则0
。slti $t0, $s2, 10
:立即数版本。sltu
/sltiu
:无符号比较。- 边界检查:
- 示例:检查
$s1 < $t2
且$s1 ≥ 0
。 - MIPS:
sltu $t0, $s1, $t2; beq $t0, $zero, IndexOutOfBounds
4. case/switch语句
- 实现:
- 转化为
if-then-else
嵌套。 - 或使用转移地址表(jump table),通过
jr
指令跳转。 - 转移地址表:存储指令序列地址的数组,程序索引表跳转。
九、硬件/软件接口
- 编译器职责:
- 变量分配寄存器,数据结构分配存储器。
- 生成分支和标签,简化程序员工作。
- 寄存器优势:
- 访问速度快、吞吐率高、功耗低。
- 编译器需高效利用寄存器,溢出变量存回存储器(spilling)。
- 指令集设计:
- 避免复杂指令(如“小于则分支”),保持简单性。
- 使用
slt
、beq
等组合实现所有比较条件。
十、总结
- 核心概念:
- 指令集是计算机与程序员的桥梁,MIPS以简洁高效著称。
- 存储程序概念赋予计算机通用性,指令和数据统一存储。
- MIPS指令集通过R型和I型格式平衡功能与简单性。
- 设计原则:
- 简单源于规整。
- 越小越快。
- 优秀设计需折中。
- 应用:
- 通过MIPS编程理解计算机硬件操作。
- 编译器优化对性能影响显著,寄存器管理是关键。