MIPS体系结构和汇编语言快速入门
MIPS 体系结构和汇编语言快速入门
译者:Sonic Fu, Northeastern University, Boston, MA, USA
译者按:有修改,无删减,初学必读。学习笔记,抛砖引玉!网上有一个老版本,不如此版全面。 英文原版: http://logos.cs.uic.edu/366/notes/mips%20quick%20tutorial.htm#IOSystemCalls
本文分3部分: 1、寄存器
2、程序结构框架 3、编写汇编程序
概要:数据类型和文法
数据类型: 字节,byte占用( 8bit ), halfword占2 byte= 16bit), word占用(4byte = 32bit) 一个字符需要一个Byte的空间;
一个整数需要1个Word(4 Byte)的空间; MIPS结构的每条指令长度都是32bit
寄存器
MIPS体系架构有32个通用寄存器。在汇编程序中,可以用编号 $0 到 $31来表示; 也可以用寄存器的名字来进行表示, 例如: $sp, $t1, $ra….
有两个特殊的寄存器 Lo, Hi, 用来保存乘法/除法的运算结果;此2寄存器不能直接寻址,
只能用特殊的指令:mfhi和mflo来aceess其中的内容。 (含义:mfhi = move from Hi, mflo = Move from Low.)
堆栈(Stack)的增长方向是: 从内存的高地址方向, 向低地址方向;
汇编程序结构框架
汇编源程序代码本质上是文本文件。由 数据声明、代码段 两部分组成。汇编程序文件应该以.s为后缀,以在Spim软件中进行模拟。(实际上ASM也行。) 数据声明部分
在源代码中,数据声明部分以 .data开始。声明了在代码中使用的变量的名字。同时,也在主存(RAM)中创建了对应的空间。 程序代码部分
在源代码中,程序代码部分以 .text开始。这部分包含了由指令构成的程序功能代码。 代码以main: 函数开始。main的结束点应该调用exit system call,参见后文有关system call 的介绍。
程序的注释部分
使用#符号进行注释。每行以#引导的部分都被视作注释。
一个MIPS汇编程序框架:
编写MIPS汇编程序:
Content:
PartI: Part II: Part III: Part IV: Part V Part VI: 数据的声明
数据的装载和保存(Load/Store 指令) 寻址
算术运算指令:Arithmetic Instructions 程序控制指令:Control Instructions 系统调用和I/O操作(
SPIM仿真)
PartI:数据的声明
创建一个以name为变量名称,values通常为初始值,storage_type代表存储类型。
Part II:数据的装载和保存(Load/Store 指令)
主存(RAM)的存取access只能用load / store 指令来完成。 所有其他的指令都使用的是寄存器作为操作数。
举个例子:
MIPS系统结构只能用load/store 相关指令来实现寻址操作,包含3中寻址方式: 装载地址:,相当于直接寻址,把数据地址直接载入寄存器。 间接寻址:,间接寻址,把寄存器内容作为地址
基线寻址/
索引寻址:based or indexed addressing,相对寻址,利用补偿值(offset)寻址。
把var1在主存(RAM
)中的地址拷贝到寄存器t0中。var1也可以是程序中定义的一个子程序标签的地址。
把t2中的字存入t0中的地址指向的主存位置。
把t0中地址+4所得的地址所对应的主存中的字载入寄存器t2中,4为包含在t0中的地址的偏移量。 store word in register $t2 into RAM at address ($t0 - 12),negative offsets are fine Note: based addressing is especially useful for: arrays; access elements as offset from base address
stacks; easy to access elements at offset from stack pointer or frame pointer 此次是负的偏移量。
注意:基线寻址在一下场合特别有用:
1、数组:从基址出发寻找数组元素,通过使用偏移量。
2、堆栈:利用从堆栈指针到框架指针之间的偏移量来读写元素。
Part IV 算术运算指令:Arithmetic Instructions
算数运算指令的所有操作数都是寄存器,不能直接使用RAM地址或间接寻址。 操作数的大小都为 Word (4-Byte)
Part V 程序控制指令:Control Instructions
子程序调用指令的实质是跳转并链接(Jump and Link), 它把当前程序计数器的值保留到$ra中,以备跳回):
sub_label为子程序的标签,如 LOOP, SUB_ROUTINE
注意,返回地址存放在$ra寄存器中。如果子程序调用了下一级子程序,或者是递归调
用,此时需要将返回地址保存在堆栈中,因为每执行一次jal指令就会覆盖$ra中的返回地址。
Part VI: 系统调用和I/O操作(SPIM仿真)
系统调用是指调用操作系统的特定子程序。
系统调用用来在仿真器的窗口中打印或者读入字符串string, 并可显示程序是否结束。 用syscall指令进行对系统子程序的调用。 本操作首先支持$v0 and $a0-$a1中的相对值
调用以后的返回值(如果存在)会保存在$v0中。
表二:系统调用的功能:
The print_string service expects the address to start a null-terminated character string. The directive .asciiz creates a null-terminated character string. 打印字符串的功能认为起始地址为一个空终止符串。声明字符串使用的.asciiz指示符会建立一个空终止符串。
The read_int, read_float and read_double services read an entire line of input up to and including the newline character.
读入整形,读入浮点型和读入双精度的功能会读取一整行,包含换行符。
The read_string service has the same semantices as the UNIX library routine fgets. It reads up to n-1 characters into a buffer and terminates the string with a null character.
If fewer than n-1 characters are in the current line, it reads up to and including the newline and terminates the string with a null character.
读入字符串的功能和UNIX库中fgets函数的语法相同。他会读入n-1个字符到缓存,然后以空字符结尾。如果少于n-1的字符,它会读到结尾并包含换行符,并以空字符结尾。
The sbrk service returns the address to a block of memory containing n additional bytes. This would be used for dynamic memory allocation.
sbrk功能返回一个包含有n个附加字节的存储区的地址,这回被用于动态内存分配。
exit功能用于停止程序运行。
e.g. Print out integer value contained in register $t2 例:打印在$t2中的整数的值