0 Preview:
MIPS架构有32位版本和64位版本,本文介绍32位版本
寄存器
正如笔者曾说,窃以为学习一款架构,首先应该学习的就是寄存器堆,会用寄存器堆,基本就能汇编语言编程,而且寄存器堆也是制作编译器的关键。
- 32个寄存器
- 3个特殊寄存器
每个寄存器都是32bits,也就是一个word
32通用
首先通过这张表格总览:
0 $zero
the constant value zero, 零号寄存器,编号为0,存储的值也永远为0,主要用于在一些指令中起辅助作用,实现复制、掩码等功能。
例1.实现分支:
1 $at
保留寄存器,用于处理32位立即数
2—3 $v0-$v1
values,用于保存函数返回值
4—7 $a0-$a3
用于保存函数的前四个参数,过程调用时不用保存,但如果是嵌套过程(即递归)就需要保存
8—15 $t0-$t7
temporaries, 用于存放一些临时产生的计算的中间结果,调用子过程的话不用保存
16—23 $s0-$s7
saved values,编译期将程序中的那些有名变量保存在 s 0 − s0- s0−s7中,调用其他过程的话需要压栈保存这些寄存器的值
24—25 $t8-$t9
t 0 − t0- t0−t7的扩充,
26—27 $k0-$k1
saved for OS kernel ,用于异常处理,
28 $gp
global pointer 全局指针,存放一个地址,指向内存中静态区(也称全局区)的中间位置,用于定位整个静态区
29 $sp
stack pointer 栈指针,存放栈顶位置,也就是内存中栈区的顶部位置,也就是栈区的地址最小的位置(栈区是栈底到栈顶地址逐渐减小)
30 $fp
frame pointer,
指令系统
掌握了各个寄存器的功能之后我们就可以学习指令系统并进行汇编编程
MIPS-32指令可以按功能划分,也可以按格式划分,也可以按寻址方式划分
寻址方式决定了这条指令写出来的样子,有时虽然同是I型指令但是写出来长得不一样
比如
lw $s1, 100($s2)
addi $s1, $s2, 100
都是I型指令,但是写出来的格式就不一样
按照寻址方式划分:
MIPS指令系统,按照寻址方式可以分为5种:
- 基址寻址
- 立即数寻址
- 寄存器寻址
- PC相对寻址
- 伪直接寻址
寄存器寻址:
add sub mul div
add $t0,$t1,$t2 #rs=$t1, rt=$t2, rd=$t0
sll (shift left logical)/srl (shift right logical)
这指令看起来像个I型但它是R型,4不是立即数,而是shamt
sll $t2, $s0, 4
AND/OR/XOR/NOT
and $t0,$t1,$t2 # $t0=$t1 & $t2
基址寻址
lw/sw
lw $t0, 32($s3)
立即数寻址
addi/subi
addi $s3,$s3,4
andi/ori
slti
slti $t0,$s2,10 # $t0=1 if $s2<10
PC相对寻址
将pc和指令中的常数相加作为寻址结果,能跳转到距离当前指令距离为±2^15个字的任何地方
这里你会发现那么指令中常数如果是1,那么代表跳一个字(也就是一条指令的长度),但是MIPS-32的存储器不是按字节寻址的么,不应该放4才代表跳一个字(一条指令)么?这里比较特殊,这里就是按字寻址的,具体可能跟汇编器的实现有关了,记住。
实际实现是,取出26位常数,左移2位乘4,然后加到pc里,
beq(branch if equal) / bne(branch if not equal)
beq register1, register2, L1
bne:branch if not equal
bne register1, register2, L2
伪直接寻址
j:jump 无条件跳转
j Exit
jal: jump and link 跳转并链接
跳转到某个地址的同时将下一条指令的地址保存在寄存器$ra中
jal ProcedureAddress
按指令格式划分:
还可以分为:
-
I型(immediate立即数)
6 5 5 16
没有rd时,rs就是源头,rt就是目的 -
R型 (Register寄存器)
6 5 5 5 5 6
三个操作数,源一,源二,目的,都是寄存器 -
J型 (Jump跳转)
6 26
其中,
R型指令:
I型指令:
lui
lui $t0, 0x1234 # rs未用,rt为
J型指令:
三种划分方式之间的联系:
这张图把IRJ和五种寻址方式这两种寻址方式联系起来了,可以看到R型指令都是寄存器寻址
但I型指令有立即数寻址,基址寻址和PC相对寻址三种寻址方式,J型指令只有伪直接寻址
而从功能上说,R型指令一般是算数运算或逻辑运算功能,I型指令一般是分支、立即数功能,J型指令一般是跳转
伪指令:
又称语法糖,就比如li指令,其实这条指令被汇编的时候会被汇编器自动转换为其他指令,它并不是一条实际存在的指令,只是方便程序员编写
move
move $destination, $source
运算
(TODO)
存储器
2^30个存储器字,一个字4字节,所以一共是4GB
使用字节编址:
- 字节编址:
你可以把MIPS-32的存储器理解为一个int数组,一个位置是32字节,也就是一个字。
但是下标不是0,1,2,,,
而是0,4,8,,,
012那叫字地址,按字寻址,MIPS-32是按字节寻址
比如你现在有个基址在$s3里存着,你想读到离这个基址8个单元远的内存块,是
lw $t0, 8($s3)
么?显然不是,应该是:
lw $t0, 32($s3)