发布时间:2025-12-09 11:55:45 浏览次数:1
1. 寄存器种类
2. 算术及寻址指令
3. 程序结构
4. 系统调用
需要使用的工具是:Mars4.4
下载地址:
http://courses.missouristate.edu/KenVollmar/mars/download.htm1 数据类型
1. 所有MIPS指令都是32位长
2. 1字节 = 8位,半字长 = 2个字节,1字长 = 4个字节
3. 一个字符空间 = 1个字节
4. 一个整型 = 一个字长 = 4个字节
5. 单个字符用单引号,例如:'b'
6. 字符串用双引号,例如:"A string"
2 寄存器
1. MIPS下一共有32个通用寄存器
2. 在汇编中,寄存器标志由$符开头
3. 寄存器表示可以有两种方式
直接使用该寄存器对应的编号,例如:从0到31
使用对应的寄存器名称,例如:t1,sp(详细名称见下表)
4. Lo和Hi寄存器专门用来存储乘法和除法的结果
对于以上两者,不存在直接寻址;必须要通过特殊指令mfhi ("move from Hi") 和 mflo ("move from Lo")来访问内容
5. 栈的走向是高地址到低地址
3 程序结构
1. 本质其实就是数据声明 + 普通文本 + 程序编码(文件扩展名为 .s或者 .asm都可以)
2. 数据声明在代码段之后(其实在之前也没啥问题,也更符合高级程序的设计习惯)
数据声明:
1. 数据段以.data为开始标志
2. 声明变量后,即在主存中分配空间
代码:
1. 代码段以 .text为开始的标志
2. 其实就是各项指令操作
3. 程序入口为main:标志(这个都一样)
4. 程序结束标志
注释:
1. 是注释符
2. MIPS程序的基本模版如下:
# Comment giving name of program and description of function# 说明下程序的目的和作用(其实和高级语言都差不多了)# Template.s# Bare-bones outline of MIPS assembly language program .data # variable declarations follow this line # 数据变量声明 # ... .text # instructions follow this line # 代码段部分 main: # indicates start of code (first instruction to execute) # 主程序 # ...# End of program, leave a blank line afterwards to make SPIM happy# 必须多给你一行,你才欢?4 数据声明
声明的格式:
name: storage_type value(s)通常给变量赋一个初始值;对于.space,需要指明需要多少大小空间(bytes)
注意:name后面始终要跟着冒号
examplevar1: .word 3 # create a single integer variable with initial value 3# 声明一个 word 类型的变量 var1, 同时给其赋值为 3array1: .byte 'a','b'# create a 2-element character array with elements initialized# to a and b# 声明一个存储2个字符的数组 array1,并赋值 'a', 'b'array2: .space 40 # allocate 40 consecutive bytes, with storage uninitialized# could be used as a 40-element character array, or a# 10-element integer array; a comment should indicate which! # 为变量 array2 分配 40字节(bytes)未使用的连续空间,当然,对于这个变量# 到底要存放什么类型的值, 最好事先声明注释下!5 加载保存【读取写入】
1. 如果要访问内存,不好意思,你只能用 load 或者 store 指令
2. 其他的只能都一律是寄存器操作
load: lw register_destination, RAM_source # copy word (4 bytes) at source RAM location to destination register. # 从内存中 复制 RAM_source 的内容到 对应的寄存器中(lw中的'w'意为'word',即该数据大小为4个字节) lb register_destination, RAM_source # copy byte at source RAM location to low-order byte of destination register,and sign-extend to higher-order bytes # 同上, lb 意为 load bytestore word: sw register_source, RAM_destination # store word in source register into RAM destination # 将指定寄存器中的数据 写入到指定的内存中 sb register_source, RAM_destination # store byte (low-order) in source register into RAM destinationload immediate: li register_destination, value # load immediate value into destination register举例
.data var1: .word 23 # declare storage for var1; initial value is 23 .text __start: lw $t0, var1 # load contents of RAM location into register $t0: $t0 = var1 li $t1, 5 # $t1 = 5 ("load immediate") sw $t1, var1 # store contents of register $t1 into RAM: var1 = $t1 done6 立即与间接寻址
load address: la $t0, var1 # 将var1的RAM地址复制到寄存器$t0中indirect addressing: lw $t2, ($t0) #将$t0中包含的RAM地址的值加载到$t2中 sw $t2, ($t0) # 将寄存器$ t2中的值存储到$ t0中包含的地址的RAM中based or indexed addressing: lw $t2, 4($t0) # 将RAM地址($t0+4)的值存到$t2寄存器 sw $t2, -12($t0) # 将$t2寄存器的值存到地址($t0-12)中不必多说,要用到偏移量的寻址,基本上使用最多的场景无非两种:数组,栈。
.data array1: .space 12 # declare 12 bytes of storage to hold array of 3 integers # 定义一个 12字节 长度的数组 array1, 容纳 3个整型 .text __start: la $t0, array1 # load base address of array into register $t0 # 让 $t0 = 数组首地址 li $t1, 5 # $t1 = 5 ("load immediate") sw $t1, ($t0) # first array element set to 5; indirect addressing # 对于 数组第一个元素赋值 array[0] = $1 = 5 li $t1, 13 # $t1 = 13 sw $t1, 4($t0) # second array element set to 13 # 对于 数组第二个元素赋值 array[1] = $1 = 13 # (该数组中每个元素地址相距长度就是自身数据类型长度,即4字节, 所以对于array+4就是array[1]) li $t1, -7 # $t1 = -7 sw $t1, 8($t0) # third array element set to -7 # 同上, array+8 = (address[array[0])+4)+ 4 = address(array[1]) + 4 = address(array[2])7 算术指令集
1. 最多3个操作数
2. 在这里,操作数只能是寄存器,绝对不允许出现地址
3. 所有的指令统一是32位 = 4 * 8 bit = 4 bytes = 1 word
add $t0,$t1,$t2 # $t0 = $t1 + $t2; add as signed (2's complement) integers sub $t2,$t3,$t4 # $t2 = $t3, $t4 addi $t2,$t3, 5 # $t2 = $t3 + 5; "add immediate" (no sub immediate) addu $t1,$t6,$t7 # $t1 = $t6 + $t7; add as unsigned integers subu $t1,$t6,$t7 # $t1 = $t6 + $t7; subtract as unsigned integers mult $t3,$t4 # multiply 32-bit quantities in $t3 and $t4, and store 64-bit # result in special registers Lo and Hi: (Hi,Lo) = $t3 * $t4 p $t5,$t6 # Lo = $t5 / $t6 (integer quotient) # Hi = $t5 mod $t6 (remainder) mfhi $t0 # move quantity in special register Hi to $t0: $t0 = Hi mflo $t1 # move quantity in special register Lo to $t1: $t1 = Lo # used to get at result of product or quotient move $t2,$t3 # $t2 = $t38 控制流
branches分支(if else系列)
指令内置了分支条件的比较:
b target # unconditional branch to program label targetbeq $t0,$t1,target # branch to target if $t0 = $t1blt $t0,$t1,target # branch to target if $t0 < $t1ble $t0,$t1,target # branch to target if $t0 <= $t1bgt $t0,$t1,target # branch to target if $t0 > $t1bge $t0,$t1,target # branch to target if $t0 >= $t1bne $t0,$t1,target # branch to target if $t0 <> $t1Jumps跳转(while,for,goto系列)
j target # unconditional jump to program label target # 看到就跳转,不用考虑任何条件 jr $t3 # jump to address contained in $t3 ("jump register") # 类似相对寻址,跳到该寄存器给出的地址处子程序调用 subroutine return: "jump register" instruction
jr $ra # "jump register"跳转到寄存器$ra中保存的返回地址(由jal指令存储)
如果说调用的子程序中有调用了其他子程序,如此往复, 则返回地址的标记就用栈(stack)来存储, 毕竟 $ra 只有一个,(哥哥我分身乏术啊)
9 系统调用和输入/输出
1. 通过系统调用实现终端的输入输出,以及声明程序结束
2. 学会使用 syscall
3. 参数所使用的寄存器:v0, a0,
4. 返回值使用:$v0
大概意思是要打印的字符串应该有一个终止符,估计类似C中的'', 在这里我们只要声明字符串为 .asciiz 类型即可。下面给个我用Mars4.4的提示:
1. 对于读取整型, 浮点型,双精度的数据操作, 系统会读取一整行,(也就是说以换行符为标志 'n')
2. read_string和fgets类似
举例 打印一个存储在寄存器$2里的整型:
Print out integer value contained in register $t2li $v0, 1 # load appropriate system call code into register $v0; # 声明需要调用的操作代码为 1 (print_int) 并赋值给 $v0 # code for printing integer is 1move $a0, $t2 # move integer to be printed into $a0: $a0 = $t2 # 将要打印的整型赋值给 $a0syscall # call operating system to perform operation举例 读取一个数,并且存储到内存中的 int_value 变量中:
Read integer value, store in RAM location with label int_value (presumably declared in data section)li $v0, 5 # load appropriate system call code into register $v0; # code for reading integer is 5syscall # call operating system to perform operationsw $v0, int_value # value read from keyboard returned in register $v0; # store this in desired location举例 打印一个字符串(这是完整的,其实上面栗子都可以直接替换main: 部分,都能直接运行
.datastring1 .asciiz "Print this.n"# declaration for string variable, # .asciiz directive makes string null terminated .text main: li $v0, 4 # load appropriate system call code into register $v0;# code for printing string is 4 la $a0, string1# load address of string to be printed into $a0 syscall # call operating system to perform print operation举例 执行到这里,程序结束,立马走人,管他后边洪水滔天~~
li $v0, 10 # system call code for exit = 10syscall # call operating sys参考引用:
本文属于转载非原创,略有修改: https://www.cnblogs.com/thoupin/p/4018455.html这篇文章的英文原版地址在这里: https://minnie.tuhs.org/CompArch/Resources/mips_quick_tutorial.html