基于MIPS的计算机指令学习(3)——指令集与汇编程序

1.汇编语言基本结构

MIPS规定编写汇编程序时要用".data"和".text"两个关键字来区分程序的数据部分和代码部分。

2.主存变量声明

由于MIPS只有32个寄存器,因此大量的变量必须存储到主存中,待需要使用时,再将其值加载到某个寄存器中。

MIPS汇编程序声明一个全局变量:变量名+存储类型+初值

例如:

str : .asciiz "1234+4321"

".asciiz"为字节为单位字符串变量的关键字,并在结尾放置一个'\0'

 注意:.space是字节数,而不是字数。

3.读存储器

1.读字节:lb(Load Byte)与lbu(Load Byte Unsigned)

从主存中读取一个字节并且将该字节写入指定的寄存器

格式:

lb rt,offset(base)

2.读半字: lh(Load Halfword)与lhu(Load Halfword Unsigned)

3.读字:lw(Load Word)

读字时从主存读出的数据是32位,而要写入寄存器的数据宽度也是32,没有符号拓展的需求,所以并不存在lwu

4.写寄存器

为读寄存器的反向操作,把数据从寄存器写入主存单元

有sb(Store Byte)、sh(Store Half)和sw(Store Word)

格式:

sb rt,offset(base)

5.寄存器加载立即数位

格式:

lui rt,immediate

这种情况下,MIPS规定立即数的长度为16位无符号数,lui执行后,指令的十六位立即数被复制到了寄存器的高16位,而寄存器的低16位则被置0

由于lui只能置高16位,因此很少被单独使用,往往与ori配对

ori格式:

ori rt,rs,imm16

rs寄存器"OR"立即数imm16,将结果写入rt寄存器

lui $s7,0x55AA

ori $s7,$s7,0x1234

$s7的值为55AA_1234

6.算术运算

6.1 加法和减法:add sub addu subu addi

add和sub会检查算术溢出,而带u则不会

MIPS规定addi的立即数是16位符号数,在编写程序时,addi的立即数范围为-32768~32767,在执行这条指令的时候,CPU首先将16位的立即数进行符号拓展成为32位

MIPS还规定了addiu等指令

6.2 乘法和除法:mult multu div divu mfhi mflo mthi mtlo

设计思想:两个32位数进行乘法运算,计算结果的最大绝对值需要64位才能表示,而一个寄存器只有32位,因此显然要用两个特定寄存器来存储高位(hi)和低位(lo)的运算结果

由于hi(HIgh)和lo(Low)不属于32个通用寄存器,因此MIPS定义了mfhi指令和mflo指令,格式如下:

mfhi rd 

mflo rd

在除法中,lo用来表示商,hi则用来表示余数

示例:

mfhi $s7                  #将乘法(除法)结果的高位(余数)传递到$s7寄存器

mthi 和mtlo两条指令不太常用,故不过多赘述

实际上还有指令mul,格式类似于add,但只能存储乘法结果的低32位

7.逻辑运算

 and/andi指令效果完全相同,区别在于andi要将第二个是立即数的运算数按0拓展方式拓展为32位立即数。

zero_ext():零拓展

sign_ext():符号拓展

8.分支指令与if-else及循环结构

8.1 基本分支指令

beq rs,rt,label

bne rs,rt,label

j label

条件分支指令:

beq: 相等则执行label(CP的值变为label后续的指令)

bne:不相等则执行

无条件分支指令:

j: 直接跳转至label处的语句

8.2 相等条件下的if-else构造方法

为了防止THEN语句即使在条件不成立的时候也执行,ELSE语句块后的j指令是必须的。

8.3 与0值比较的条件分支指令

blez:小于等于0转移

bgtz:大于0转移

bltz:小于0转移

bgez:大于等于0转移

格式:

blez rs,label

8.4 两个非0值的不等条件的if-else构造方法

出于性能方面的考虑,MIPS中没有提供可“通用”的指令,而是提供了slt这一比较大小的指令

 a<b 直接用slt比较

a>b 用slt判断b<a

a<=b 对b<a的结果进行取反

a>=b 对a<b的结果进行取反

slt将判断后的结果储存在rd寄存器中,再运用beq和bne指令结合$0就可以实现对应的条件转移

8.5 while循环

首尾两行定义while的边界,通过组合b类指令以及slt类指令实现当循环条件不满足时跳出循环

8.6 for循环

for类似于while,需要在循环体被执行前测试条件,因此b类指令必须部署在循环体之前,循环体后通常放置循环变量赋值语句,并在循环外先初始化循环变量。

9.伪指令

9.1 move: 寄存器间赋值

move $dst,$src

将src寄存器赋值给dst寄存器

等效于

add $s0,$s1,$0

9.2 li:加载立即数到寄存器

(16位)

li $t0,-100

等效于

addiu $t0,$0,-100

32位立即数时编译器通过lui和ori两条指令实现

9.3 la:加载地址到寄存器

la 寄存器,内存变量名

10.移位指令

方向:向左还是向右移位

性质:逻辑移位还是算术移位(带不带符号)

移位量:(1)由五位的立即数表示移位量

              (2)由寄存器的后五位表示移位量

11.系统调用与输入输出

   此部分内容可参考(27条消息) MIPS编程入门_子曰小玖的博客-CSDN博客_mips编程

  • 通过系统调用实现终端的输入输出,以及声明程序结束
  • 学会使用 syscall
  • 参数所使用的寄存器:$v0, $a0,  $a1
  • 返回值使用: $v0

下表给出了系统调用中对应功能,代码,参数机返回值

Service

Code
in $v0

对应功能的调用码

Arguments

所需参数

Results

返回值

print_int

打印一个整型

$v0 = 1

$a0 = integer to be printed

将要打印的整型赋值给 $a0

print_float

打印一个浮点

$v0 = 2

$f12 = float to be printed

将要打印的浮点赋值给 $f12

print_double

打印双精度

$v0 = 3

$f12 = double to be printed

将要打印的双精度赋值给 $f12

print_string

$v0 = 4

$a0 = address of string in memory

将要打印的字符串的地址赋值给 $a0

read_int

$v0 = 5

integer returned in $v0

将读取的整型赋值给 $v0

read_float

读取浮点

$v0 = 6

float returned in $v0

将读取的浮点赋值给 $v0

read_double

读取双精度

$v0 = 7

double returned in $v0

将读取的双精度赋值给 $v0

read_string

读取字符串

$v0 = 8

$a0 = memory address of string input buffer

将读取的字符串地址赋值给 $a0
$a1 = length of string buffer (n)

将读取的字符串长度赋值给 $a1

sbrk

应该同C中的sbrk()函数

动态分配内存

$v0 = 9

$a0 = amount

需要分配的空间大小(单位目测是字节 bytes)

address in $v0

将分配好的空间首地址给 $v0

exit

退出

$v0 =10

打印一个存储在寄存器$s2的整型:

li $v0,1                #将要打印$a0

move $a0,$s2     #将$s2的值传递给$a0

syscall                #系统执行IO操作

读取一个数,并储存在$s0中:

li $v0,5                #将要进行读取

syscall                #系统执行IO操作(返回值就存储在$v0中)

move $v0,$s0     #把$v0的值传递给$s0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值