MIPS 体系结构和汇编语言快速入门(翻译)
译者:Sonic Fu, Northeastern University, Boston, USA
译者按:学习笔记,抛砖引玉!网上有一个版本,不全,这个作为补充。
英文原版: http://logos.cs.uic.edu/366/notes/mips quick tutorial.htm#IOSystemCalls
本文分3部分: 0、引子, 1、寄存器介绍 2、I/O介绍
引子:数据类型和文法
数据类型: 字节,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)的增长方向是: 从内存的高地址方向, 向低地址方向;
表格1:寄存器的编号名称及分类
编号 寄存器名 寄存器描述
0 Zero 第0号寄存器,其值始终为0
1 $at (Assembler Temporary) 是Assembler保留的寄存器
2 ~ 3 $v0 ~ $v1 (values)保存表达式或函数返回的结果
4-7 $a0 - $a3 (arguments) 作为函数的前四个入参。在子函数调用的过程中不会被保留。
8-15 $t0 - $t7 (temporaries) Caller saved if needed. Subroutines can use without saving.
供汇编程序使用的临时寄存器。在子函数调用的过程中不会被保留。
16-23 $s0 - $s7 (saved values) - Callee saved.
A subroutine using one of these must save original and restore it before
exiting. 在子函数调用的过程中会被保留。
24-25 $t8 - $t9 (temporaries) Caller saved if needed. Subroutines can use without saving.
供汇编程序使用的临时寄存器。在子函数调用的过程中不会被保留。这是对 $t0 -
$t7的补充。
26-27 $k0 - $k1 保留,仅供中断(interrupt/trap)处理函数使用.
28 $gp global pointer. 全局指针。Points to the middle of the 64K block of memory in the
static data segment.指向固态数据块内存的64K的块的中间。
29 $sp stack pointer 堆栈指针, 指向堆栈的栈顶。
30 $s8/$fp saved value / frame pointer保存的值/帧指针
Preserved across procedure calls其值在函数调用的过程中会被保留
31 $ra return address返回地址
汇编程序结构框架
汇编源程序代码本质上是文本文件。由数据声明、代码段 两部分组成。程序文件应该以.s结尾,以在Spim软件中进行模拟。
数据声明部分
在源代码中,数据声明部分以 .data开始。声明了在代码中使用的变量的名字。同时,也在主存(RAM)中创建了对应的空间。
程序代码部分
在源代码中,程序代码部分以 .text开始。这部分包含了由指令构成的程序功能代码。
代码以main: 函数开始。main的结束点应该调用exit system call,参见后文有关system call 的介绍。
程序的注释
使用#符号进行注释。每行以#引导的部分都被视作注释。
一个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
开始编写MIPS汇编程序:
Content:
数据的声明
程序代码的编写
Part I: 数据的装载和保存(Load/Store 指令)
Part II: 寻址 :只能用load/store 相关指令来实现寻址操作
Part III: 算术相关的指令:Arithmetic Instructions
数据的声明:
格式:
name: storage_type value(s)
创建一个以name为变量名称,values通常为初始值,storage_type代表存储类型。
注意:变量名后要跟一个:冒号
#example:
#-------------------------------------------------------------------------------------
var1: .word 3 # create a single integer:
#variable with initial value 3
array1: .byte 'a','b' # create a 2-element character
# array with elements initialized:
# to a and 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 it.
string1 .asciiz "Print this.n" #declare a string
#-------------------------------------------------------------------------------------
程序代码的编写:
Part I:数据的装载和保存(Load/Store 指令)
主存(RAM)的存取access只能用load / store 指令来完成。
所有其他的指令都使用的是寄存器作为操作数。
i. load指令:
lw register_destination, RAM_source
# copy word (4 bytes) at
# source_RAM location
# to destination register.
# load word -> lw
lb register_destination, RAM_source
# copy byte at source RAM
# location to low-order byte of
# destination register,
# and sign -e.g. tend to
# higher-order bytes
# load byte -> lb
li register_destination, value
#load immediate value into
#destination register
#load immediate --> li
ii. store指令:
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
#destination
举个例子:
#-------------------------------------------------------------------------------------
.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 done
done
#-------------------------------------------------------------------------------------
Part II:寻址 :(
只能用load/store 相关指令来实现寻址操作)
装载地址:load address:
la
$t0, var1
把var1在主存(RAM)中的地址拷贝到寄存器t0中。var1也可以是程序中定义的一个子程序标签的地
址。
间接寻址:indirect addressing:
lw
$t2, ($t0)
主存中有一个字的地址存在t0中,按这个地址找到那个字,把字拷贝到寄存器t2中。
sw $t2, ($t0)
把t2中的字存入t0中的地址指向的主存位置。
基线寻址/索引寻址:based or indexed addressing:
lw $t2, 4($t0)
把t0中地址+4所得的地址所对应的主存中的字载入寄存器t2中,4为包含在t0中的地址的偏移量。
sw $t2, -12($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、堆栈:利用从堆栈指针到框架指针之间的偏移量来读写元素。
举个例子:
#-------------------------------------------------------------------------------------
#example
.data
array1: .space 12 # declare 12 bytes of storage
# to hold array of 3 integers
.text
__start:
la $t0, array1 # load base address of array
# into register $t0
li $t1, 5 # $t1 = 5 ("load immediate")
sw $t1, ($t0) # first array element set to 5;
# indirect addressing
li $t1, 13 # $t1 = 13
sw $t1, 4($t0) # second array element set to 13
li $t1, -7 # $t1 = -7
sw $t1, 8($t0) # third array element set to -7
done
#-------------------------------------------------------------------------------------
Part III 算术相关的指令:Arithmetic Instructions
算数运算指令的所有操作数都是寄存器,不能直接使用RAM地址或间接寻址。
操作数的大小都为 Word (4-Byte)
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
div $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 = $t3
# ----------------------------------(To becontinued)---------------------------------------------------