MARS帮助文档整理_基础指令
// 根据MARS源文档进行字典序排列,为方便理解有一些顺序调动,以供学习参考
// 如有错误,请不吝赐教
*$f_
-> 浮点数寄存器(后面的数字单双表示单双精度)
*$t
-> 整数寄存器
*PC
(Program Counter):用于存储当前CPU正在执行的指令在内存中的地址
*协同处理器Coprocessor被缩写为Coproc
或者c
或者CP
*其他对操作数描述的详尽说明:
abs.d $f2, $f4
$f2 = |$f4|(双精度)
abs.s $f0, $f1
$f0 = |$f1|(单精度)
格式 | 功能概述 | 备注 |
---|---|---|
add $t1, $t2, $t3 | $t1 = $t2 + $t3 | 考虑溢出的整数加法 |
add.d $f2, $f4, $f6 | $f2 = $f4 + $f6 | 双精度浮点数加法 |
add.s $f0, $f1, $f3 | $f0 = $f1 + $f3 | 单精度浮点数加法 |
addi $t1, $t2, -100 | $t1 = $t2 + 一个16位有符号立即数 | -32768 ~ 32767,考虑溢出的整数加法 |
addiu $t1, $t2, -100 | $t1 = $t2 + 一个16位无符号立即数 | 0 ~ 65535,无溢出检测的整数加法 |
addu $t1, $t2, $t3 | $t1 = $t2 + $t3 | 无溢出检测的整数加法 |
// 无符号Unsigned是一种误导,意思就是不考虑溢出
and $t1, $t2, $t3
按位与 : $t1 = $t2 & $t3
andi $t1, $t2, 100
跟一个16位无符号立即数的按位与:$t1 = $t2 & 一个16位无符号立即数(对此数进行0扩展以后再进行运算)
-
跳啊跳啊_Branch
和PC相关的相对寻址指令(地址计算依赖于PC值)称为分支(branch),助记词以b开头。
格式 功能概述 备注 bc1f 1, label
如果 1
处表示的具体状态标记flag
(Condition Flag)的值是false
,也即0,则跳转到地址在label中的语句注意是 bc1f
, 不要把数字1
写成字母l
,下同(其实只要记住c1指代的是Coprocessor1就可以);同时注意示例中的1
表示的是状态标记,可以是0 ~ 7
的任意数字,可以参见MARS寄存器状态栏中的Coproc 1
一栏bc1f label
如果 Coproc 1
中的flag 0(也即状态栏中的$f0
)值为false
,也即0,则跳转到地址在label中的语句Branch if Crproc1 False bc1t 1, label
如果 1
处表示的具体状态标记flag
的值是true
,也即1,则跳转到地址在label中的语句bc1t label
如果 Coproc 1
中的flag 0(也即状态栏中的$f0
)值为true
,也即1,则跳转到地址在label中的语句Branch if Crproc1 True beq $t1, $t2, label
如果 $t1 = $t2,则跳转到地址在label中的语句 Branch if EQual bgez $t1, label
如果 $t1 >= 0,则跳转到地址在label中的语句 Branch if Greater than or Equal to Zero bgezal $t1, label
如果 $t1 >= 0, 则PC跳转到地址在label中的语句(可以是一个子程序,比如test),无论调用是否发生,返回地址一律保存到寄存器 $ra
中。Branch if Greater than or Equal to Zero And Link bgtz $t1, label
如果 $t1 > 0,则跳转到地址在label中的语句 Branch if Greater Than Zero blez $t1, label
如果 $t1 <= 0,则跳转到地址在label中的语句 Branch if Less than or Equal to Zero bltz $t1, label
如果 $t1 < 0,则跳转到地址在label中的语句 Branch if Less Than Zero bltzal $t1, label
如果 $t1 >= 0, 则PC跳转到地址在label中的语句(可以是一个子程序,比如test),无论调用是否发生,返回地址一律保存到寄存器 $ra
中。Branch if Less Than Zero And Link bne $t1, $t2, label
如果 $t1 != $t2,则跳转到地址在label中的语句 Branch if Not Equal -
停止执行_Break
break
终止异常执行的程序的运行break 100
以指定的异常码(16位无符号数)终止异常执行的程序的运行 -
比较_Compare
格式 功能概述 备注 c.eq.d $f2, $f4
如果**$f2 = $f4**,将 Coproc1
中的flag 0
置1
(true
),否则置0
(false
)d:双精度浮点数比较,下同 c.eq.d 1, $f2, $f4
如果**$f2 = $f4**,将 Coproc1
中的flag 0
置立即数表示的具体数值(true
),否则置0
(false
)c.eq.s $f0, $f1
如果**$f0 = $f1**,将 Coproc1
中的flag 0
置1
(true
),否则置0
(false
)s:单精度浮点数比较,下同 c.eq.s 1, $f0, $f1
如果**$f0 = $f1**,将 Coproc1
中的flag 0
置立即数表示的具体数值(true
),否则置0
(false
)c.lt.d $f2, $f4
如果**$f2 < $f4**,将 Coproc1
中的flag 0
置1
(true
),否则置0
(false
)c.lt.d 1, $f2, $f4
如果**$f2 < $f4**,将 Coproc1
中的flag 0
置立即数表示的具体数值(true
),否则置0
(false
)c.lt.s $f0, $f1
如果**$f0 < $f1**,将 Coproc1
中的flag 0
置1
(true
),否则置0
(false
)c.lt.s 1, $f0, $f1
如果**$f0 < $f1**,将 Coproc1
中的flag 0
置立即数表示的具体数值(true
),否则置0
(false
) -
向上取整_Ceil
ceil.w.d $f1, $f2
置$f1为双精度浮点数$f2的向上取整的结果(一个32位整数 → word)ceil.w.s $f0, $f1
置$f0为单精度浮点数$f1的向上取整的结果(一个32位整数) -
计算前导数_Count number of Leading x
clo $t1, $t2
置$t1为$t2的从最高有效位开始的前导1个数clz $t1, $t2
置$t1为$t2的从最高有效位开始的前导0个数 -
转换_Convert
留意一下转换规律就好了。前面那个是待置的(d to double, s to single, w to word)。
格式 功能概述 备注 cvt.d.s $f2, $f1
置$f2为与单精度浮点数$f1等值的一个双精度浮点数 cvt.d.w $f2, $f1
置$f2为与32位整数$f1等值的一个双精度浮点数 cvt.s.d $f1, $f2
置$f1为与双精度浮点数$f2等值的一个单精度浮点数 cvt.s.w $f0, $f1
置$f0为与32位整数$f2等值的一个单精度浮点数 cvt.w.d $f0, $f2
置$f0为与双精度浮点数$f2等值的一个32位整数 cvt.w.s $f0, $f1
置$f0为与单精度浮点数$f1等值的一个32位整数 -
除法_Div
格式 功能概述 备注 div $t1, $t2
将$t1除以$t2,然后置 LO 为商,置 HI 为余数(用 mfhi
访问HI,mflo
访问LO)考虑溢出的除法 div.d $f2, $f4, $f6
置$f2为 $f4 ÷ $f6
的双精度浮点数结果两个双精度浮点数的除法 div.s $f0, $f1, $f3
置$f0为 $f1 ÷ $f3
的双精度浮点数结果两个单精度浮点数的除法 divu $t1, $t2
将无符号数$t1除以$t2,然后置 LO 为商,置 HI 为余数(用 mfhi
访问HI,mflo
访问LO)不考虑溢出的除法 -
异常返回_Exception RETurn
eret
将PC设置为Coproc 0
(协处理器) 中epc
寄存器的值,并将其中status
寄存器的位 1(异常级别)置为0// 可以在MARS的
Coproc 0
栏中找到这两个寄存器 -
向下取整_Floor
floor.w.d $f1, $f2
置$f1为双精度浮点数$f2的向下取整的结果(一个32位整数 → word)floor.w.s $f0, $f1
置$f0为单精度浮点数$f1的向下取整的结果(一个32位整数) -
跳啊跳啊_Jump
绝对地址指令(地址计算不依赖PC值)称为跳转(Jump),助记词以j开头。(注意跟Branch区分)
格式 | 功能概述 | 备注 |
---|---|---|
j target | 跳转到target 的地址 | 无条件跳转 Jump |
jal target | 置$ra 为PC的返回地址,然后跳转到地址在target 中的语句 | Jump And Link |
jalr $t1 | 置$ra 为PC的返回地址,然后跳转到地址在t1 中的语句 | Jump And Link Register |
jalr $t1, $t2 | 置$t1 为PC的返回地址,然后跳转到地址在t2 中的语句 | |
jr $t1 | 跳转到地址在t1 中的语句 | 无条件跳转 Jump Register |
-
加载_Load
格式 功能概述 备注 lb $t1, -100($t2)
将 $t1 置为来自有效内存字节地址的符号扩展的 8 位值,或者说,是把内存中地址为 x + $t2
的数取出来,进行符号扩展扩为8位也即一个字节后,放到$t1里去Load Byte(最后扩展完毕得到的是8位的值,也即一个字节);-100表达的是一个16位有符号整数x(-32768 ~ 32767);常见的用法有令x = 4,这样可以一直往下访问 lbu $t1, -100($t2)
将 $t1 置为来自有效内存字节地址的0扩展的 8 位值,或者说,是把内存中地址为 x + $t2
的数取出来,进行0扩展扩为8位也即一个字节后,放到$t1里去无符号unsigned即做0扩展,没什么好说的 ldc1 $f2, -100($t2)
置FPU寄存器$f2为来自有效内存双字地址(2 * 32 = 64位)的64位值 $f2来自 Corproc 1
lh $t1, -100($t2)
为16位值,其他描述同第一行的lb Load Half Word lhu $t1, -100($t2)
为16位值,其他描述同第二行的lbu ll $t1, -100($t2)
跟 sc
(Store Conditional)配对进行RMW操作。ll
指令负责从内存中读取一个字,以实现接下来的 RMW(Read-Modify-Write,读改写) 操作,而sc
指令的功能是向内存中写入一个字,以完成前面的 RMW 操作。Load Link,在MARS中视为等同于加载字 ( lw
),因为 MARS 不模拟多个处理器。
它们不是一个简单的内存读取/写入的函数,当使用ll
指令从内存中读取一个字之后, 处理器会记住这次操作(会在 CPU 的寄存器中设置一个不可见的 bit 位),同时这次操作读取的地址也会保存在处理器的寄存器中。 接下来的sc
指令,比如 会检查上次ll
指令执行后的 RMW 操作是否是原子操作(即不存在其它对这个地址的操作), 如果是则 t 的值将会被更新至内存中,同时 t 的值也会变为1,表示操作成功; 反之(即存在其它对这个地址的访问冲突),则 t 的值不会被更新至内存中,且 t 的值也会变为0,表示操作失败。lui $t1, 100
将$t1的高16位置为后面的16位立即数(100表示的),低16位置0 Load Upper Immediate lw $t1, -100($t2)
为32位值,其他描述同第一行的lb Load Word lwc1 $f1, -100($t2)
为32位值,其他描述同第三行的ldc1 Load Word Coproc 1 lwl $t1, -100($t2)
对于大端:从所指位置(地址)向高地址方向取数直至地址对齐,且按从低地址至高地址的顺序将数据排序,将排序好的数据存放在寄存器 $t1
的高位。
对于小端:从所指位置(地址)向低地址方向取数直至地址对齐,且按从高地址至低地址的顺序将数据排序,将排序好的数据存放在寄存器$t1
的高位。Load Word Left lwr $t1, -100($t2)
对于大端:从所指位置(地址)向低地址方向取数直至地址对齐,且按从低地址至高地址的顺序将数据排序,将排序好的数据存放在寄存器 $t1
的低位。
对于小端:从所指位置(地址)向高低址方向取数直至地址对齐,且按从高地址至低地址的顺序将数据排序,将排序好的数据存放在寄存器$t1
的低位Load Word Right -
乘加_Multiply Add
madd $t1, $t2
将$t1乘以$t2,然后HI增上乘积的高32位,LO增上乘积的低32位(记得用mfhi
访问HI,mflo
访问LO)maddu $t1, $t2
无符号,没什么好说的(前面都有) -
移来移去_Move
格式 功能概述 备注 mfc0 $t1, $8
置$t1的值为CP0寄存器 $8
中储存的值在MARS中,它是 vaddr
Move From Coproc 0mfc1 $t1, $f1
置$t1的值为CP1寄存器(FPU寄存器)$f1中储存的值 Move From Coproc 1 mfhi $t1
置$t1的值为HI中的内容 用于乘除运算 mflo $t1
置$t1的值为LO中的内容 同上 mov.d $f2, $f4
置$f2的值为$4中存储的值 双精度浮点数 mov.s $f0, $f1
置$f0的值为$f1中存储的值 单精度浮点数 movf $t1, $t2
如果FPU寄存器的状态标志0(flag 0)值为 false
,则置 t 1 为 t1为 t1为t2的值movf $t1, $t2, 1
如果具体指定的( 1
表示的0 ~ 7的任意一个数字)FPU寄存器状态标志(flag x)的值为false
,则置$t1为$t2的值movf.d $f2, $f4
形式基本同上 movf.d $f2, $f4, 1
形式基本同上 movf.s $f0, $f1
形式基本同上 movf.s $f0, $f1, 1
形式基本同上 movn $t1, $t2, $t3
如果$t3不为0,则置$t1为$t2的值 movn.d $f2, $f4, $t3
形式基本同上 movn.s $f0, $f1, $t3
形式基本同上 movt $t1, $t2
如果FPU寄存器的状态标志0(flag 0)值为 true
,则置$t1为$t2的值movt $t1, $t2, 1
如果具体指定的( 1
表示的0 ~ 7的任意一个数字)FPU寄存器状态标志(flag x)的值为true
,则置$t1为$t2的值movt.d $f2, $f4
形式基本同上 就都是浮点数精度问题了,后面也不备注了 movt.d $f2, $f4, 1
形式基本同上 movt.s $f0, $f1
形式基本同上 movt.s $f0, $f1, 1
形式基本同上 movz $t1, $t2, $t3
如果$t3 = 0,则置$t1为$t2的值 movz.d $f2, $f4, $t3
形式基本同上 movz.s $f0, $f1, $t3
形式基本同上 mtc0 $t1, $8
置CP0寄存器 $8
(vaddr
)为$t1中存储的值Move To Coprocessor 0 mtc1 $t1, $f1
置CP1寄存器 $f1
(FPU寄存器)为$t1中存储的值Move To Coprocessor 1 mthi $t1
置HI为$t1中存储的值 乘除运算中用 mtlo $t1
置LO为$t1中存储的值 乘除运算中用 -
乘减_Msub
msub $t1, $t2
将$t1乘以$t2,然后HI减掉乘积的高32位,LO减掉乘积的低32位(记得用mfhi
访问HI,mflo
访问LO)msubu $t1, $t2
无符号,没什么好说的 -
乘法_Mul
mul $t1, $t2, $t3
将$t2 * $t3的高32位存在HI中,低32位存在LO和$t1中,不考虑溢出(mfhi
访问HI,mflo
访问LO)
mul.d $f2, $f4, $f6
$f2 = $f4 * $f6(双精度浮点数乘法)
mul.s $f0, $f1, $f3
$f0 = $f1 * $f3(单精度浮点数乘法)
mult $t1, $t2
将$t1 * $t2的高32位存在HI中,低32位存在LO中,不考虑溢出(mfhi
访问HI,mflo
访问LO)
multu $t1, $t2
无符号,没什么好说的
-
浮点数取反_Neg
neg.d $f2, $f4
置$f2为双精度浮点数$f4取反的结果neg.s $f0, $f1
置$f0为单精度浮点数$f1取反的结果 -
无操作_Nop
nop
机器码全为0,空操作 -
或非_Nor
nor $t1, $t2, $t3
置$t1为 $t2或非$t3 的结果 -
或运算_Or
or $t1, $t2, $t3
置$t1为 $t2 | $t3 的结果ori $t1, $t2, 100
置$t1为 $t2 | 16位无符号立即数x(进行0扩展)的结果 -
浮点数的舍入_Round
round w.d $f1, $f2
将双精度舍入到字 : 置$f1为$f2中的双精度浮点数的32位整数舍入值round w.s $f0, $f1
将单精度舍入到字 : 置$f0为$f1中的单精度浮点数的32位整数舍入值 -
存储_Store
sb $t1, -100($t2)
将$t1中的低8位存储到有效内存字节地址中去,或者说,是把$t1中的低8位存储到内存中地址为x(有符号16位整数) + $t2
的地方去,store byte
sc $t1, -100($t2)
跟ll
指令搭配完成读改写任务,详见前文的ll
指令部分(Store Conditional)
sdcl $f2, -100($t2)
将CP1寄存器$f2(FPU寄存器)中的64位值存储到有效内存字节地址中去,或者说,是把$f2中的64位值存储到内存中地址为x(有符号16位整数) + $t2
的地方去,store Doubleword
sh $t1, -100($2)
将$t1中的低16位存储到有效内存字节地址中去,或者说,是把$t1中的低16位存储到内存中地址为x(有符号16位整数) + $t2
的地方去,store Halfword
sw $t1, -100($t2)
将$t1中的值(32位)存储到有效内存字节地址中去,或者说,是把$t1中的值存储到内存中地址为x(有符号16位整数) + $t2
的地方去,store Word
swc1 $f1, -100($t2)
将CP1寄存器$f1(FPU寄存器)中的32位值存储到有效内存字节地址中去,或者说,是把$f1中的32位值存储到内存中地址为x(有符号16位整数) + $t2
的地方去,store Word
swl $t1, -100($t2)
将 $t1 的高位1到4字节(4 * 8 = 32)存储到内存中:从高到低分别就是从有效字节地址,也就是内存中地址为x(有符号16位整数) + $t2
的地方开始,一直到这个“字”的低位字节,等效于在有效字节地址里存了这个字的“左边”, store word left
swr $t1, -100($t2)
大致同上,只不过是反过来取了$t1的低位1到4字节,等效于在有效字节地址存了这个字的“右边”,store word right
sll $t1, $t2, 10
将$t2左移x(无符号5位整数,0 ~ 31)位的结果存储到$t1中,逻辑左移操作
sllv $t1, $t2, $t3
大体同上,只不过左移的位数由5位立即数变为$t3中低5位存储的值
sra $t1, $t2, 10
将$t2算术右移x(无符号5位整数,0 ~ 31)位的结果做符号扩展后存储到$t1中
srav $t1, $t2, $t3
大体同上,只不过右移的位数由5位立即数变为$t3中低5位存储的值
srl $t1, $t2, 10
将$t2左移x(无符号5位整数,0 ~ 31)位的结果存储到$t1中,逻辑右移操作
srlv $t1, $t2, $t3
大体同上,只不过右移的位数由5位立即数变为$t3中低5位存储的值
-
小于则置_Set Less Than
slt $t1, $t2, $t3
如果$t2 < $t3,则置$t1为1
,否则置为0
(可以看作一个判断)sltu $t1, $t2, $t3
大体同上,但注意这里是无符号比较!slti $t1, $t2, -100
大体同slt
,只不过$t3换成一个做了符号扩展的16位有符号整数sltiu $t1, $t2, -100
大体同上,但注意这里是无符号比较! -
开方_Sqrt
sqrt.d $f2, $f4
置$f2为双精度浮点数$f4开方的结果,也是一个双精度浮点数sqrt.s $f0, $f1
换成单精度而已,没什么好说的 -
减法_Sub
sub $t1, $t2, $t3
置$t1为 $t2 - $t3 的值(考虑溢出)subu $t1, $t2, $t3
类似,不考虑溢出的结果sub.d $f2, $f4, $f6
类似,双精度浮点数的减法结果sub.s $f0, $f1, $f3
类似,单精度浮点数的减法结果 -
Syscall
syscall
发出系统调用,执行$v0中的值指定的系统调用 (在后续的Syscalls模块中将具体提到不同的$v0的值会引发怎样的操作) -
自陷_Trap
TEQ、TNE等都是条件自陷指令。如果条件成立就会引发一个自陷(Trap)异常。自陷指令又叫做访管指令,出现在计算机操作系统中,用于实现在用户态下运行的进程调用操作系统内核程序,即当运行的用户进程或系统实用进程欲请求操作系统内核为其服务时,可以安排执行一条陷入指令引起一次特殊异常。通常自陷指令是给编译器和解释器用的,可以实现运行时数组边界检查之类的操作。
指令差异都是对大小等关系的判断,以及无符号、立即数这老几样,不具体列出了。