mips体系结构--汇编

指令集

指令集是存储在CPU内部,对CPU运算进行指导和优化的硬程序。拥有这些指令集,CPU就可以更高效地运行。

Mips汇编语言的风格
汇编语言指令格式
[标签:] 操作符 [操作数] [#注释]
标签: (可选)
标记内存地址, 必须跟冒号
通常在数据和代码段出现
操作符
定义操作 (比如add, sub, 等)
操作数
指明操作需要的数据
操作数可以是寄存器,内存变量或常数
大多数指令有3个操作数

# this is acomment
entrypoint:         # that’s a label
add $1 , $2,$3  # (registers) $1 = $2 + $3
 
# —— 注释
xxx:—— 定义代码的人口点和命名数据段的存储段

程序结构

汇编语言的程序结构,为数据声明+普通文本+程序编码(文件后缀为.s,或者.asm也行),数据声明在代码段之后(其实在其之前也没啥问题,也更符合高级程序设计的习惯)

数据声明

 数据段以 .data为开始标志
 声明变量后,即在主存(RAM)中分配空间。

Example:

var1:                 
.word         3       # 声明一个 word 类型的变量 var1,同时给其赋值为 3
array1:             
.byte         'a','b' # 声明一个存储2个字符的数组array1,并赋值 'a','b'
array2:             
.space       40     #为变量 array2 分配40字节(bytes)未使用的连续空间,当然,对于这个变量

    
代码:

 代码段以 .text为开始标志
 其实就是各项指令操作
 程序入口为main:标志(这个都一样啦)
 程序结束标志(详见下文)

其他:

.data       //数据段
.text       //代码段
.globl      //全局符号声明
.align  n   //n字节对齐
.asciiz      //字符串(带终止符)
.ent main    //main函数的开始
.type  main, @function //类型,指定为函数,但是也可以是变量
.set   noreorder       //设置属性为不优化代码
.set   reorder            //设置属性为优化代码

寄存器

32个通用寄存器:
MIPS的寄存器约定,一种32个寄存器

0                zero:总返回0
1                at:  (汇编暂存寄存器)为汇编保留
2-3            v0、v1:存放子函数调用返回结果,还可用于表达式求值
4-7            a0- a3:存放向子函数传递的参数
8-15          t0-t7:存放临时运算结果,在发生函数调用时不必保存它们的内容
24,25        t8-t9:
16-23        s0 - s7:存放局部变量,在发生函数调用时一般要保存它们的内容
26,27        k0, k1:为中断/陷入处理保留,你也可以改变
28             gp:全局指针
29              sp:       栈(stack)指针
30              s8/fp:       帧(frame)指针
31              ra:       返回地址(用于过程调用

寄存器名约定与使用

*at: 这个寄存器被汇编的一些合成指令使用。如果你要显示的使用这个寄存器(比如在异常处理程序中保存和恢复寄存器),有一个汇编directive可被用来禁止汇编器在directive之后再使用at寄存器(但是汇编的一些宏指令将因此不能再可用)。

*v0, v1: 用来存放一个子程序(函数)的非浮点运算的结果或返回值。如果这两个寄存器不够存放需要返回的值,编译器将会通过内存来完成。

*a0-a3: 用来传递子函数调用时前4个非浮点参数。在有些情况下,这是不是绝对的。请参10.1细节。

* t0-t9: 依照约定,一个子函数可以不用保存并随便的使用这些寄存器。在作表达式计算时,这些寄存器是非常好的暂时变量。编译器/程序员必须注意的是,当调用一个子函数时,这些寄存器中的值有可能被子函数破坏掉。

*s0-s8: 依照约定,子函数必须保证当函数返回时这些寄存器的内容必须恢复到函数调用以前的值,或者在子函数里不用这些寄存器或把它们保存在堆栈上并在函数退出时恢复。这种约定使得这些寄存器非常适合作为寄存器变量或存放一些在函数调用期间必须保存原来值。

* k0, k1: 被OS的异常或中断处理程序使用。被使用后将不会恢复原来的值。因此它们很少在别的地方被使用。

* gp: 如果存在一个全局指针,它将指向运行时决定的,你的静态数据(static data)区域的一个位置。这意味着,利用gp作基指针,在gp指针32K左右的数据存取,系统只需要一条指令就可完成。如果没有全局指针,存取一个静态数据区域的值需要两条指令:一条是获取有编译器和loader决定好的32位的地址常量。另外一条是对数据的真正存取。为了使用gp, 编译器在编译时刻必须知道一个数据是否在gp的64K范围之内。通常这是不可能的,只能靠猜测。一般的做法是把small global data (小的全局数据)放在gp覆盖的范围内(比如一个变量是8字节或更小),并且让linker报警如果小的全局数据仍然太大从而超过gp作为一个基指针所能存取的范围。

并不是所有的编译和运行系统支持gp的使用。

*sp: 堆栈指针的上下需要显示的通过指令来实现。因此MIPS通常只在子函数进入和退出的时刻才调整堆栈的指针。这通过被调用的子函数来实现。sp通常被调整到这个被调用的子函数需要的堆栈的最低的地方,从而编译器可以通过相对於sp的偏移量来存取堆栈上的堆栈变量。详细可参阅10.1节堆栈使用。

* fp: fp的另外的约定名是s8。如果子函数想要在运行时动态扩展堆栈大小,fp作为桢指针可以被子函数用来记录堆栈的情况。一些编程语言显示的支持这一点。汇编编程员经常会利用fp的这个用法。C语言的库函数alloca()就是利用了fp来动态调整堆栈的。

如果堆栈的底部在编译时刻不能被决定,你就不能通过sp来存取堆栈变量,因此fp被初始化为一个相对与该函数堆栈的一个常量的位置。这种用法对其他函数是不可见的。

* ra: 当调用任何一个子函数时,返回地址存放在ra寄存器中,因此通常一个子程序的最后一个指令是jr ra.

子函数如果还要调用其他的子函数,必须保存ra的值,通常通过堆栈。

数据类型

MIPS CPU的一次操作可加载或存储1到8个字节的数据。
MIPS名称大小(字节)汇编器助记符

dword         8       “d”代表ld
word           4       “w”代表lw
halfword     2       “h”代表lh
byte            1       “b”代表lb

操作指令

SPIM是一个很小,简单的mips汇编的模拟器

加载和存储(load、store)

Load

在一个内存地址加载word/halfword/byte的数据到一个寄存器

lw r, aRßa
lh r, a 无符号
lb r, a 无符号
lhu     有符号
lhbu   有符号
li r,c   加载立即数

Store

将寄存器中的数据存储到内存地址
sw r, aRàa
sh r, a Store low halfword
sb r, a Store low byte

Move:

寄存器之间数据的直接交换
move r , sRßs

逻辑运算

and r, s, tR ßs . t
or r, s, t  Rßs + t
not r, s   Rßs取反
xor r, s, t Rßs异或t
nor r, s, tRß(s+t)再取反

算数运算

add r, s, tRßs + t
sub r, s, t Rßs – t
mul r, s, tRßs*t
div r, s, t Rßs/t

hi和lo乘法器相关的寄存器规模结果接口,不能用于乘和除之外的操作。对于以上二者,不存在直接寻址;必须要通过mfhi("move from hi")以及mflo("move from lo")两条指令分别来进行访问对应的内容。
乘法——将两个整数的相乘结果分成两部分存储的指定的寄存器里。
除法——lo寄存器存储结果(商),hi寄存器存储余数。

移位操作

sll r, s, c r ← shift s left c bits
srl r, s, cr ← shift s right c bits

分支操作

通过条件判断,使程序跳转到tag

b tag          跳转àtag
beq r, s, tagR=s àtag
beqz r, tagR=0 àtag
bne r, s, tagR != sàtag
bgt r, s, tagR > s àtag
bge r, s, tagR >=s àtag
blt r, s, tagR < s àtag
ble r, s, tagR<=sàtag

比较指令

slt r, s, t   S < t
sle r, s, t  S <= t
sgt r, s, t S >t
sge r, s, tS >= t
seq r, s, tS = t
sne r, s, tS != t
l  FALSE    r ß 0
l  TRUE     r ß 1

寻址方式

² 直接寻址:

MIPS只有一种寻址方式。任何加载或存储机器指令可以写成
lw $1, offset($2)
你可以使用任何寄存器来作为目标和源寄存器。offset偏移量是一个有符号的16位
的数字(因此可以是在-32768与32767之间的任何一值)。用来加载的程序地址是源寄
存器与偏移量的和所构成的地址。
($t0) —— 默认从0地址偏移$t0字节

² 访问连续的内存空间:

根据程序的实际需要可能进行字符串等数据的访问。

.ascii s                        ASCIIencoded characters of string s
.asciiz s                      like .ascii,null-terminated
.word w1, w2,…        32-bit words w1, w2,. . .
.half h 1, h 2, . . .       16-bithalfwords h 1, h 2, . . .
.byte b1, b2, . . .        8-bit bytes b1,b2, . . .
.float f1, f2, . . .         32-bit singleprecision floating point numbers f1, f2, . . .
.double d1, d2, . . .    64-bit doubleprecision floating point numbers d1, d2, . . .
.space n                     n zero bytes

例如:
.data
str: .asciiz "hello word"

系统调用:syscall

MIPS 提供一条特殊的 syscall指令,从操作系统获取服务
使用 syscall系统服务
从 $v0寄存器中读取服务数
从 $a0,$a1, 等寄存器中读取参数值(如果有)
发送 syscall指令
从结果寄存器中取回返回值(如果有)
$v0 中包含调用号(共12个):

Service          $v0Arguments / Result
Print Integer 1    $a0 = integer value to print
Print Float     2    $f12 = float value to print
Print Double 3    $f12 = double vlaue to print
Print String   4    $a0 = address of null-terminated string
Read Integer5    $v0 = integer read
Read Float    6    $f0 = float read
Read Double7    $f0 = double read
Read String  8    $a0 = address of input buffer
                           $a1 = maximum number of characters to read
Exit Program10
Print Char     11  $a0 = character to print
Read Char    12  $a0 = character read

程序调用
jal a(jump and link)将程序跳转到地址a并将下一条指令的地址存储在$ra寄存器中
j $ra返回到程序跳转时的位置,无条件跳转

延迟槽:分支延迟
在所有的MIPS CPU里,紧跟着跳转指令的指令(在延迟槽中)会被CPU执
行,即使已经分支。程序员或编译器必须找到一个有用的,至少是无害的指令
放在延迟槽中——在最差的情况下加入一条nop指令。但是,除非你指定,汇编器将会使得跳转延迟是透明不可见的。

内存空间

MipsCPU 可以运行两种特权级别上:用户态和核心态。我经常提到用户模式和核心模式,但事实上,从核心态切换到用户态,MIPS CPU做的工作并没有不同,只是有时是非法的。在用户态,任何一个地址的首地址是非法的,就会引起陷阱异常。另外,在用户态下,一些指令也会引起异常。
在32位视图中,程序地址空间划分位4个大区域。

      +----------------------------------------------+
      |                       | 0xFFFFFFFF
      |                       |
      |                       |
      | Kernel SpaceMapped Cached   kseg2      |
      |                       |
      |                       |
0xC0000000 |                         |
      +----------------------------------------------+
      |                       | 0xBFFFFFFF
      | Kernel Space Unmapped Uncached  kseg1        |
      |                       |
0xA0000000+----------------------------------------------+
      |                       | 0x9FFFFFFF
      | Kernel Space Unmapped Cached    kseg0     |
      |                       |
0x80000000+----------------------------------------------+
      |                       | 0x7FFFFFFF
      |                       |
      |                       |
      |                       |
      |    User Space             kuseg       |
      |                       |
      |                       |
      |                       |
      |                       |
      |                       |
0x00000000+----------------------------------------------+

User mode(kuseg)

从0x00000000到0x7FFFFFFF的这一段空间,为User Space,可以在User Mode下访问,当然,在Kernel Mode下也是可以访问的。程序在访问User Space的内存时,会通过MMU的TLB,映射到实际的物理地址上。也就是说,这一段逻辑地址空间和物理地址空间的对应关系,是由MMU中的TLB表项 决定的。

Kernel mode

从0x80000000到0xFFFFFFFF的一段为Kernel Space,仅限于Kernel Mode访问。如果在User Mode下试图访问这一段内存,将会引发系统的一个Exception。MIPS的  Kernel Space又可以划分为三部分。

Kseg0:

在内核模式中,当虚拟地址的最高3bit有效位是100,32位的KSEG0虚拟地址空间被选择;它位于地址2^29 - bit(512M)内核虚拟空间0x8000_0000 - 0x9FFF_FFFF。引用KSEG0未映射(即不经过TLB的转换);所选的物理地址是
通过从虚地址中减去0x8000_0000限定。访问 kseg1的数据会缓存到 cache ,在配置寄存器的K0控制其缓存能力。
通过高速缓存,对这段区域内的地址进行访问。因此,在缓存未进行适当的初始化之前,不要使用这些地址。在有MMU的系统中,操作系统的内核会存放在这个区域。

Kseg1:

在内核模式中,当32位虚拟地址的最高3bit的有效位是101,32位的KSEG1
虚拟地址空间被选择。 KSEG1是位于2^29 - bit(512M)内核的虚拟空间地址0xA000_0000 - 0xBFFF_FFFF。引用KSEG1未映射;的物理地址的选择是通过从虚地址中减去0xA000_0000限定。引用这个区域是始终未缓存。
因此,你可以使用这段地址空间来访问你的初始程序的ROM。还有大多数人把它用来访问I/O寄存器。

Kseg2:

当32位虚拟地址的最高3bit的有效位是110,32位的KSEG1
虚拟地址空间被选择。这段地址空间只能在核心态下使用,要经过MMU映射到物理地址的1GB空间,地址范围从0xC0000000到0xFFFFFFFF。这1GB空间可以用来访问实际的DRAM内存,可以为操作系统的内核所用。

转自: 林风专栏
原文链接: http://blog.csdn.net/sdreamq/article/details/50776361

--电子创新网--
粤ICP备12070055号