恩,是的,这节是介绍Sparc指令的。Sparc我就不介绍了,我工作使用的芯片是Sparc平台的Leon3,做嵌入式的当然逃不了汇编,了解是必需的。
以下的算是上几个星期的工作总结了。发现错误发email指正,感激不尽。
SPARC是CPU指令集架构的一种,其设计的目标是优化的编译和易用的流水线硬件执行。
SPARC指令集有以下主要特点:
1. 线性的32位地址空间
2. 精简的指令格式
所有指令都是32位宽和以32为分界对齐排列的。只有3个基本指令的格式--它们是非统一的操作数位置和寄存器地址域。特别要注意的是:只有load和store指令能访问memory和I/O。
3. 很少的几个地址模式,总之比x86指令的地址模式少得多
要么是"register+register",要么是"register+immediate"。
4. 三个一组的寄存器地址
很多指令操作是基于2个寄存器操作数,和一个存放运算结果的寄存器。
例如:add %1,%2,%3 !%1+%2->%3
5. A large “windowed” register file — At any one instant, a program sees 8 global integer registers plus a 24-register window into a larger register file. The windowed registers can be described as a cache of procedure arguments, local values, and return addresses. (这里的register file就是寄存器文件,寄存器是寄存器文件的简称。感谢CU的jamesr告诉我这一点)
6. A separate floating-point register file
通过软件将(浮点数)配置成32单精度(32bit),16双精度(64bit),8四倍精度寄存器(128bit),或将它们混合。
7. 延时控制传输----处理器常常是在一个延时控制传输指令后提取下一个指令。依靠控制传输指令的"annul"位判断是否执行它。
8. 多处理器同步指令----一个指令执行一个原子的‘读-然后-设置存储’的操作;另一个执行原子的‘寄存器与存储器交换’的操作。
9. 协处理器 (由于我使用的芯片上没有,所以关于它的指令就不介绍了 )
SPARC寄存器组
寄存器是位于cpu片上的存储单元。在SPARC架构中有32个通用的integer寄存器和32个浮点寄存器。在此之前,强烈推荐Peter Magnusson的一篇入门文章《Understanding stacks and registers in the Sparc architecture(s)》。
Interger通用寄存器组
32个通用的integer寄存器名为%r0,%r01,%r2,… %r31。(由于它们在程序中运行的不同目的,又给它们起了各自的别名,peter哥的文章有介绍)
浮点寄存器组
它们是%f0 .. %f31,通常用于支持实数。它们可用于成对和成组(4个) 的很大的一个数的存储。
专用寄存器组
%psr 处理器状态寄存器(Processor State Register)
%wim 窗口无效屏蔽寄存器(Window Invalid Mask Register)
%tbr Trap基址寄存器(Trap Base Register)
%y Y寄存器(Y register)
%y寄存器用于乘法和除法中。在除法中,暂存被除数的高32位有效位;
在乘法中,暂存乘积的高32位有效位;
%fsr 浮点状态寄存器(Floating-Point State Register)
%csr 协处理器状态寄存器(Coprocessor-State Register)
%fq 浮点指针队列寄存器(Floating-Point Queue)
%cq 协处理器队列寄存器(Coprocessor Queue)
%hi,%lo 用于一元操作,截取操作数的高22位和低10位。 (一般用来配合sethi指令)
指令分类及指令格式
1.指令分类及简介
SPARC指令集可以分为6大组类:load/store指令、整数运算指令、控制传输(CTI)指令、读/写控制寄存器指令、浮点操作和协处理器操作指令。
2.指令格式
SPARC指令使用的基本格式如下:
Opcode {rs1, rs2(imm), rd}
操作数的个数根据不同类型的指令而不同,由0~3个不等。如nop,是无操作数的。
基本指令格式说明指今格式中所用的英文编写符号说明如下:
Opcode 操作码,指令助记符,如LD、ST、ADD等
Rs1: 源操作数寄存器1内容。
Rs2: 源操作数寄存器2内容。
Imm: 立即数
Rd: 目标寄存器
基本格式中“{}”和“()”的说明:
“{ }”内的项是项是可选的,例如,{rs1, rs2, rd}为指令操作数可能没有或有1~3个。
“( )”表示或者,如“rs2(imm)”为要么是寄存器操作数,要么是立即数。 3.格式使用举例
指令格式举例如下:
add %l2, %l3, %g3 ! 本地寄存器%l2,加上%l3,结果存入到全局寄存器%g3
! 中
ld [%g3], %fsr ! 读取g3地址的存储单元内容,放入到浮点状态寄存
! 器fsr中
st %fsr, [%o2] ! 把fsr中的内容,存到输出寄存器%o0内容所指地址
! 的存储单元中。
subcc %g0, %o2, %g0 ! %g0和%o2的减法运算,并对状态寄存器的条件码作
! 相应操作
bne ,a s1f ! 分支指令,如果%o2不为零,则跳到标识符为s1处。
好了,经过上面那么枯燥的介绍,下面来点更枯燥的。
SPARC寻址方式
寻址方式是根据指令编码中给出的地址码字段来寻找真实操作数的方式。SPARC处理器支持的基本寻址方式很简单,其存储器地址的给出,要么是"register+register",要么是"register+immediate"。基本的寻址方式有以下几种。
1.立即寻址
立即寻址也称为立即数寻址,是一种特殊的寻址方式。操作数是直接通过指令给出,数据就包含在指令的32位编码中,只要取出指令就可在指令执行时得到立即操作数。例如指令:
add %o1, 1, %o1 ! %o1 ← %o1 + 1
and %o2,0x0f,%o3 ! %o3 ← %o2 AND “0x0f”
需要注意的是,在SPARC体系中,只有第二个操作数才会用到立即寻址方式。那么,SPARC处理器是如何识别立即数的呢,这要结合SPARC指令编码格式来说明(参看V8手册 )。其实,在有两个源操作数的指令编码格式中,有一位“i”标志符起了决定性的作用。i 用于为(整数)算术运算和load/store指令选择第二个运算器操作数。如果 i = 0,操作数是寄存器r[rs2];如果 i = 1,操作数是有符号立即数simm13,符号扩展从 13~32 bit。
2.立即数的值
另外值得注意的是立即数的取值范围,在SPARC体系中,依不同的指令类型而不同。并用于不同的寻址模式中。
imm7:取值范围在 -64 ~ 127 之间的立即数(用7位表示,有符号或无符号)。常用于(trap)跟踪类型指令的偏址寻址方式中。
uimm7:取值范围在0 ~ 127之间的立即数(用7位表示,无符号)。用于偏址寻址方式中。
simm13:取值范围在 -4096 ~ 4095之间的立即数(用13位表示,有符号)。当i=1,用于算术运算指令或load/store指令的第二个运算器操作数。
const22:用22