思维导图
一.引言
指令是机器语言的基本组成单位,是一串二进制码.各种各样的指令使得机器进行不同的操作.由一个机器所有指令的集合,就叫做指令集.当前流行的指令集有ARM7,ARM8,MIPS,Intel x86,本文以MIPS指令集举例.
存储程序:我们将一系列的指令和数据以数字形式存放于存储器中,就成为了存储程序,以便于日后使用
寄存器:寄存器的主要功能就是用于数据的快速存取,刚才说到了存储程序,大量的数据其实是放在存储器中的,如何获取这些数据呢,就得使用寄存器了.机器可以利用寄存器中的数据执行指令,那么寄存器是不是越多越好呢?当然不是,使用寄存器的目的在于快速的存取数据,所以,过多的寄存器也不好,目前的寄存器的数量一般是32个.此外有一个寄存器的值$zero恒为0.
存储器:在寄存器中提到,存储器存储了大量的数据,此外,还可以储存数据结构,等等.
二.计算机硬件的操作数
- 字:由于寄存器的大小为32位,所以每次获取数据的大小不会超过32位,所以将每次获取的32位数据成为字,字就是获取数据单位.在下文中,用$t x 表示储存临时数据的寄存器,用$s x表示存储非临时数据的寄存器.
- 存储器操作数:为了同存储器获取或者存储数据,就会使用到数据传输指令,而数据传输指令会指定特定的地址,以获取或者储存数据.常用的数据传输指令是lw(load word)和sw(store word).
//数据传输指令
//以下两条指令完成了从存储器中的某个位置获取数据,然后又将此数据存入此位置的操作
//加载数据指令,其中$s0称为基址寄存器,用于储存基础地址,比如数组的起始地址,8称为偏移量,两者共同确认地址
lw $t0,8($s0)
//存储数据指令
sw t0,8($s0)
- 立即数操作数:如果没有立即数操作数,当我们希望将一个寄存器上的值加或减一个值的时候,我们需要使用数据传输指令从存储器中获取数据再使用算术指令,立即数操作数可以取代这个步骤,直接使用立即数操作数指令执行算术操作.
//如果使用立即数操作数,希望$s0的值+1
//首先获取值为1的地址,然后储存在临时寄存器中
lw $t0,32($s0)
//将$s1的值加一,意思是将$s1这个寄存器的值+1,然后储存在$s2中,第一个$s1是目标寄存器
add $s2,$s1,$t0
//如果使用立即数操作数的话
addi $s2,$s1,1
- 有符号数和无符号数:二进制数是一串0,1的排列,在MIPS中,最左边叫做最高有效位,最右边叫做最低有效位.因为计算机需要对正数和负数进行计算,所以需要一种方法来表示正数和负数.当不需要表示负数的时候,32位都是有效数字,称为无符号数.在指令命名中,一般使用u表示,比如,lbu,指加载无符号字节.
- 符号和幅值表示法:这是早先使用的方法,他会添加一个符号位用于表示正数和负数,但是添加在最左边还是最右边成了问题,还会发生+0和-0的问题,所以符号和幅值表示法逐渐被放弃.
- 二进制补码:使用前导位表示正负数,符号位(前导位)是0表示正数,前导位是1表示负数.符号位是有效值前的所有数字.如果一个数字没有32位,只有16,则需要进行符号扩展.具体操作是将此值的符号位最高有效位扩充16位.
//特别说明,前导位是指有效数字之前的所有数字
//这是1,前导位位0,说明是+1
0000 0000 0000 0000 0000 0000 0000 0001
//-1的表示方法,没有有效数字,所以有效数字是0,对负数求值需要取反,然后+1.
1111 1111 1111 1111 1111 1111 1111 1111
//这也是最大正数比负数少一的原因
//最大正数
0111 1111 1111 1111 1111 1111 1111 1111
//最大负数
1000 0000 0000 0000 0000 0000 0000 0000
//符号扩展
//初始值,1
0000 0000 0000 0001
//符号扩展为32位
0000 0000 0000 0000 0000 0000 0000 0001
三.计算机中指令的表示
首先,指令是有格式的,指令的长度也可以通过将二进制变为16进制或者其他进制来改变.
//二进制 1
0000 0000 0000 0000 0000 0000 0000 0001
//十六进制
0000 0001
3.1指令类型
以下是常用的指令
- 3.1.1算术指令
//加法,将寄存器s1,s2的值相加赋值到t0中
add $t0,$s1,$s2
//减法,将寄存器s1,s2的值相减赋值到t0中
sub $t0,$s1,$s2
//立即数加法,因为可以使用负数,所以没有立即数减法
//s1的是加上4赋值给t0
addi $t0,$s1,4
- 3.1.2数据传输指令
//加载数据指令
lw $t0,8($s0)
//存储数据指令
sw t0,8($s0)
//当然还要其他的数据传输指令比如lh $s1,20($2)是取半字指令,lb取字节,lbu取无符号字节ll取连接等等
- 3.1.3逻辑指令
逻辑指令分为移位和按位两种.
//移位指令,使得数据x2的冥或者/2的冥更加高效
//逻辑左移指令,将s1的左移4位储存在s0中,即将s1的值x2的4次方=16
sll $s0,$s1,4
//逻辑右移指令
srl $s0,$s1,4
------------------------------------------------------------------
//按位指令
//按位与,操作位均为1是结果为1,否则为0,有立即数指令
and $t0,$t1,$t2
addi $t0,$t1,1
//按位或,操作位任意为1结果为1,均为0则结果为0,有立即数指令
or $t0,$t1,$t2
ori $t0,$t1,1
//按位取反,操作位为1,结果为0,操作位为0,结果为1
not $t0,$t1
//按位或非,将后两个寄存器的值取或操作后再取反,赋值到$t0上
nor $t0,$t1,$t2
//按位异或,操作位不同结果为1,相同则结果为0
xor $t0,$t1,$t2
- 3.1.4决策指令
汇编语言中没有循环,switch这些语法,只有相等,不等,跳转至某个标签,并使用这些命令构造循环或者switch语句.
//判断指令,模拟以下java代码,其中a,b,c,d,e的值以储存在寄存器$s1,$s2,$s3,$s4,$s5中
if(a == b){
c = d + e;
}else{
c = d - e;
}
----------------------------------------------
//不等指令bne,branch if not equal,如果不等,则跳转到Else标签,此标签会在以后定义
bne $s1,$s2,Else
//如果相等,则执行add执行
add $s3,$s4,$s5
//跳转指令,跳转到指定标签Exit
j Exit
//Else标签定义
Else:sub $s3,$s4,$s5
//Exit标签定义
Exit:
----------------------------------------------
//同理,循环语句和switch语句也通过同样的方法构造
----------------------------------------------
//还有小于则置位指令,若s4小于s5,将s3设置为1,否则为0
slt $s3,$s4,$s5
//可以使用无符号数
sltu $s3,$s4,$s5
//也可以使用立即数
slti $s3,$s4,5
//或者两者结合
sltiu $s3,$s4,5
----------------------------------------------
//其他的跳转语句,跳转至指定寄存器位置,用于switch语句
jr $ra
//跳转并链接,用于过程调用
jal 200
3.2指令格式
现在说说为什么用$s x 和$t x表示寄存器了,在MIPS的指令格式中,$s0-$s7 用16-23表示,$t0-$t7用8-15表示
指令格式有三种
- R型
OP | RS | RT | RD | SHAMT | FUNCT |
6位 | 5位 | 5位 | 5位 | 5位 | 6位 |
- op: 操作码,确定使用哪个指令
- rs:第一个源操作数寄存器
- rt:第二个源操作数寄存器
- rd:用于存放操作结果的目的寄存器,举例:add $t0,$s1,$s2,$t0是rd,$t0,$s1是rs和rt
- shamt:表示位移指令中的位移量比如sll $t0,$s1,4 的shamt就是4
- funct:功能码,表示特定op字段的特定变式
- I型
OP | RS | RT | 常量值或者地址 |
6位 | 5位 | 5位 | 16位 |
当使用取字指令时,如果偏移量相当的大,大于32(5bit的最大值 0001 1111),R型指令就不能完成此功能,所以I型指令将RT后的字段全部设置为一个字段用于表示常量值或者地址,其他字段的功能则没有发生变化.此时偏移量或者地址的最大值就是2^15
- J型
OP | ADRESS |
6位 | 26位 |
J型指令则是专门用于跳转指令,指定相当大的偏移量.
以下是常用指令指令及其格式
四.MIPS 指令集
MIPS 指令集(共31条) |
|||||||||
助记符 |
指令格式 |
示例 |
示例含义 |
操作及其解释 |
|||||
Bit # |
31..26 |
25..21 |
20..16 |
15..11 |
10..6 |
5..0 |
|||
R-type |
op |
rs |
rt |
rd |
shamt |
func |
|||
add |
000000 |
rs |
rt |
rd |
00000 |
100000 |
add $1,$2,$3 |
$1=$2+$3 |
rd <- rs + rt ;其中rs=$2,rt=$3, rd=$1 |
addu |
000000 |
rs |
rt |
rd |
00000 |
100001 |
addu $1,$2,$3 |
$1=$2+$3 |
rd <- rs + rt ;其中rs=$2,rt=$3, rd=$1,无符号数 |
sub |
000000 |
rs |
rt |
rd |
00000 |
100010 |
sub $1,$2,$3 |
$1=$2-$3 |
rd <- rs - rt ;其中rs=$2,rt=$3, rd=$1 |
subu |
000000 |
rs |
rt |
rd |
00000 |
100011 |
subu $1,$2,$3 |
$1=$2-$3 |
rd <- rs - rt ;其中rs=$2,rt=$3, rd=$1,无符号数 |
and |
000000 |
rs |
rt |
rd |
00000 |
100100 |
and $1,$2,$3 |
$1=$2 & $3 |
rd <- rs & rt ;其中rs=$2,rt=$3, rd=$1 |
or |
000000 |
rs |
rt |
rd |
00000 |
100101 |
or $1,$2,$3 |
$1=$2 | $3 |
rd <- rs | rt ;其中rs=$2,rt=$3, rd=$1 |
xor |
000000 |
rs |
rt |
rd |
00000 |
100110 |
xor $1,$2,$3 |
$1=$2 ^ $3 |
rd <- rs xor rt ;其中rs=$2,rt=$3, rd=$1(异或) |
nor |
000000 |
rs |
rt |
rd |
00000 |
100111 |
nor $1,$2,$3 |
$1=~($2 | $3) |
rd <- not(rs | rt) ;其中rs=$2,rt=$3, rd=$1(或非) |
slt |
000000 |
rs |
rt |
rd |
00000 |
101010 |
slt $1,$2,$3 |
if($2<$3) |
if (rs < rt) rd=1 else rd=0 ;其中rs=$2,rt=$3, rd=$1 |
sltu |
000000 |
rs |
rt |
rd |
00000 |
101011 |
sltu $1,$2,$3 |
if($2<$3) |
if (rs < rt) rd=1 else rd=0 ;其中rs=$2,rt=$3, rd=$1 |
sll |
000000 |
00000 |
rt |
rd |
shamt |
000000 |
sll $1,$2,10 |
$1=$2<<10 |
rd <- rt << shamt ;shamt存放移位的位数, |
srl |
000000 |
00000 |
rt |
rd |
shamt |
000010 |
srl $1,$2,10 |
$1=$2>>10 |
rd <- rt >> shamt ;(logical) ,其中rt=$2, rd=$1 |
sra |
000000 |
00000 |
rt |
rd |
shamt |
000011 |
sra $1,$2,10 |
$1=$2>>10 |
rd <- rt >> shamt ;(arithmetic) 注意符号位保留 |
sllv |
000000 |
rs |
rt |
rd |
00000 |
000100 |
sllv $1,$2,$3 |
$1=$2<<$3 |
rd <- rt << rs ;其中rs=$3,rt=$2, rd=$1 |
srlv |
000000 |
rs |
rt |
rd |
00000 |
000110 |
srlv $1,$2,$3 |
$1=$2>>$3 |
rd <- rt >> rs ;(logical)其中rs=$3,rt=$2, rd=$1 |
srav |
000000 |
rs |
rt |
rd |
00000 |
000111 |
srav $1,$2,$3 |
$1=$2>>$3 |
rd <- rt >> rs ;(arithmetic) 注意符号位保留 |
jr |
000000 |
rs |
00000 |
00000 |
00000 |
001000 |
jr $31 |
goto $31 |
PC <- rs |
I-type |
op |
rs |
rt |
immediate |
|||||
addi |
001000 |
rs |
rt |
immediate |
addi $1,$2,100 |
$1=$2+100 |
rt <- rs + (sign-extend)immediate ;其中rt=$1,rs=$2 |
||
addiu |
001001 |
rs |
rt |
immediate |
addiu $1,$2,100 |
$1=$2+100 |
rt <- rs + (zero-extend)immediate ;其中rt=$1,rs=$2 |
||
andi |
001100 |
rs |
rt |
immediate |
andi $1,$2,10 |
$1=$2 & 10 |
rt <- rs & (zero-extend)immediate ;其中rt=$1,rs=$2 |
||
ori |
001101 |
rs |
rt |
immediate |
andi $1,$2,10 |
$1=$2 | 10 |
rt <- rs | (zero-extend)immediate ;其中rt=$1,rs=$2 |
||
xori |
001110 |
rs |
rt |
immediate |
andi $1,$2,10 |
$1=$2 ^ 10 |
rt <- rs xor (zero-extend)immediate ;其中rt=$1,rs=$2 |
||
lui |
001111 |
00000 |
rt |
immediate |
lui $1,100 |
$1=100*65536 |
rt <- immediate*65536 ;将16位立即数放到目标寄存器高16 |
||
lw |
100011 |
rs |
rt |
immediate |
lw $1,10($2) |
$1=memory[$2 |
rt <- memory[rs + (sign-extend)immediate] ;rt=$1,rs=$2 |
||
sw |
101011 |
rs |
rt |
immediate |
sw $1,10($2) |
memory[$2+10] |
memory[rs + (sign-extend)immediate] <- rt ;rt=$1,rs=$2 |
||
beq |
000100 |
rs |
rt |
immediate |
beq $1,$2,10 |
if($1==$2) |
if (rs == rt) PC <- PC+4 + (sign-extend)immediate<<2 |
||
bne |
000101 |
rs |
rt |
immediate |
bne $1,$2,10 |
if($1!=$2) |
if (rs != rt) PC <- PC+4 + (sign-extend)immediate<<2 |
||
slti |
001010 |
rs |
rt |
immediate |
slti $1,$2,10 |
if($2<10) |
if (rs <(sign-extend)immediate) rt=1 else rt=0 ; |
||
sltiu |
001011 |
rs |
rt |
immediate |
sltiu $1,$2,10 |
if($2<10) |
if (rs <(zero-extend)immediate) rt=1 else rt=0 ; |
||
J-type |
op |
address |
|||||||
j |
000010 |
address |
j 10000 |
goto 10000 |
PC <- (PC+4)[31..28],address,0,0 ;address=10000/4 |
||||
jal |
000011 |
address |
jal 10000 |
$31<-PC+4; |
$31<-PC+4;PC <- (PC+4)[31..28],address,0,0 |