杂事太多,浪费我10多天的时间。ARM指令集,我感觉还是“复杂”了;功能虽全,但记忆量也多。其实,编写OS所用到的只是100多条ARM指令集中的约30多条吧。以下是对ARM指令集的第一次简单整理,有错难免、仅供参考。
有多种指令集架构(Instruction Set Architecture),如RISC类(RISC-V、OpenRISC、ARM( Advanced RISC Machines) 、MIPS、等等精简指令集架构)、Intel x86 体系(可变指令长度的CISC(复杂指令集计架构,Complex Instruction Set Architecture))。一个机器内也可以支持多种指令集架构,如ARM的A(Application profile)系列CPU(基于MMU(内存管理单元)支持VMSA(虚拟内存系统架构))内就可以支持A64/A32/T32三种指令集架构。AArch64 state(状态)支持A64指令集,这是一个固定长度32位指令编码的指令集;AArch32 state支持:A32、一个固定长度的32位指令编码的指令集,与ARMv7 ARM指令集兼容;T32、是一个可变长度使用16位和32位指令编码的指令集,与ARMv7 Thumb®指令集兼容。16位指令编码空间有64K条机器指令码,32位指令编码空间可以有4G条机器指令码。汇编语言是为了方便人们记忆和使用各种指令集的语言,一条汇编语言指令语句通常是表述一束指令码(包含多条类同功能的机器指令码),如MOVT Rd, #imm16; 16位立即数送到目标32位寄存器Rd的高16位、就代表了一束指令(14*64K条机器指令码)。将汇编语句翻译成机器可以认知的机器指令码的软件就是汇编语言编译器。通常有五类指令:控制指令,转移指令,数据处理指令,存储器访问指令,向量操作类指令(可伸缩向量SVE指令集,SIMD向量(Single-Instruction、Multiple-Data)和标量floating-point(浮点),基本的数字信号处理DSP(digital signal processing)指令)(另文讨论)。
ARM汇编指令的基本格式:
}{
}{
• 其中尖括号是必须的,花括号是可选的。
• A32: Rd => {R0–R14} ,注:也有许多指令的Rd可以是R15 = PC。
• A64: Rd =>Xt => {X0–X30}
注意:如比较、测试等指令是没有目标寄存器的。通常的实际写法有3种:
Opcode {Cond}{S} Rd, Operand2;
Opcode {Cond}{S} Rn, Operand2;
Opcode {Cond}{S} Rd, Rn, Operand2;
Opcode:操作码助记符,说明指令需要执行的操作类型,如ADD等。
Cond:指令执行条件码,通常是条件跳转和少数数据处理这类指令才有条件执行;A32有更多的条件指令,但实现复杂,并没有明显好处。Cortex‐M3中,只有转移指令(B 指令)才可随意使用条件后缀。而对于其它指令,CM3 引入了 IF‐THEN 指令块,在这个块中才可以加后缀,且必须加以后缀。另外,S 后缀可以和条件后缀在一起使用。共有 15 种不同的条件后缀。
q:“.W(Wide)”后缀指定 32 位指令。如果没有给出后缀,汇编器会先试着用 16 位指令以缩小代码体积,如果不行再使用 32 位指令。因此,使用“.N”(N=Narrow)其实是多此一举,或说{}项后缀多余。
S:条件码设置项,决定本次指令执行是否影响PSTATE寄存器相应状态位值,如ADDS R0,R1 ; 根据加法的结果更新 APSR 中的标志。
Rd/Xt:目标寄存器,A32指令可以选择R0-R14;T32的16位指令大部分只能选择RO-R7,32 位指令则无限制,A64指令可以选择X0-X30。
Rn/Xn:第一个操作数的寄存器,和Rd一样,不同指令有不同要求。
Operand2:灵活的第二个操作数,可以是立即数(常量constant),寄存器Rm和寄存器移位方式(Rm, shift)。(shift应用于Rm的可选移位ASR #sh(允许移动1–32位)、LSR #sh(允许移动1–32位)、LSL #sh(允许移动0–31位)、ROR #sh(允许移动1–32位)、RRX(向右循环移动一位,带扩展);type Rs仅在ARM中使用,type:是ASR、LSR、LSL或ROR,Rs提供移位量的ARM寄存器、只使用最低有效字节。)
Operand2 =
ARM汇编指令格式:
**Opcode{Cond}{S} {Rd,} Rn{, Operand2};**
算术逻辑单元ALU(Arithmetic Logical Unit),应用程序状态寄存器APSR(Application Program Status Register),当前程序状态寄存器CPSR(Current PSR),保存的程序状态寄存器SPSR。
1)、加减算术运算指令:(C进位,!为取反)
Opcode {S}{Cond} Rd, Rn, Operand2; Rd = Rn Opcode Operand2。
ADD{S}{Cond} Rd, Rn, Operand2; 加法,Rd = Rn + Operand2。
ADC{S}{Cond} Rd, Rn, Operand2; 带进位加法,Rd = Rn + Operand2 + C。
SUB{S}{Cond} Rd, Rn, Operand2; 减法(substract),Rd = Rn - Operand2。
SBC{S}{Cond} Rd, Rn, Operand2; 带进位减法(substract with carry ),Rd = Rn - Operand2 - !C。
RSB{S}{Cond} Rd, Rn, Operand2; 逆向减法(Reverse subtract)。Rd = Operand2 - Rn
RSC{S}{Cond} Rd, Rn, Operand2; 带进位逆向减法(Reverse subtract with carry),Rd = Operand2 - Rn - !C。
2)、饱和SAT(saturate)加减运算指令:有符号限幅最大正值或最小负值,无符号限幅2^n - 1或0(负值)。
Opcode{Cond} Rd, Rn, Rm; Rd = SAT( Rn Opcode Rm )
QADD{Cond} Rd, Rn, Rm; 饱和加法,Rd = SAT( Rn + Rm )。
QDADD{Cond} Rd, Rn, Rm; 饱和加倍加法,Rd = SAT( Rn + SAT( 2*Rm ) )。
QSUB{Cond} Rd, Rn, Rm; 饱和减法,Rd = SAT( Rn - Rm )。
QDSUB{Cond} Rd, Rn, Rm; 饱和加倍减法,Rd = SAT( Rn - SAT( 2*Rm ) )。
有符号或无符号饱和到任何位的位置,可选择在饱和前进行移位。
Opcode{Cond} Rd, #SAT, Rm, shift}; Opcode = SSAT、USAT。#SAT指定要饱和到的位位置,SSAT范围:1--32,USAT范围:0--31。Rm、Rd不能为PC(R15)。shift是一个可选的移位,ASR #n; (ARM n = 1--32,T32 n = 1--31),LSR #n; (n = 0--31)。
SSAT{Cond} Rd, #SAT, Rm, shift}; 有符号(Signed Sat)饱和字、移位,Rd = SignedSat((Rm, ASR|LSR #sh), #sat)。
USAT{Cond} Rd, #SAT, Rm, shift}; 无符号(Unsigned Sat)饱和字、移位,Rd = UnsignedSat((Rm, ASR|LSR #sh), #sat)。
并行半字饱和指令(同时高低2个半字):
Opcode {Cond} Rd, #SAT, Rm; Opcode= SSAT16(Signed Sat16)有符号饱和、USAT16(Unsigned Sat16)无符号饱和。#SAT指定要饱和到的位位置,SSAT16范围:1--16,USAT16范围:0--15。Rm、Rd不能为PC(R15)。
SSAT16{Cond} Rd, #SAT, Rm; 有符号饱和两个半字,Rd[31:16] = SignedSat(Rm[31:16], #sat),Rd[15:0] = SignedSat(Rm[15:0], #sat)。
USAT16{Cond} Rd, #SAT, Rm; 无符号饱和两个半字,Rd[31:16] = UnsignedSat(Rm[31:16], #sat),Rd[15:0] = UnsignedSat(Rm[15:0], #sat)。
3)、并行加减算术运算指令:
Opcode {Cond} Rd, Rn, Rm;
并行指令前缀():
S: 对2^8 or 2^16有符号求模,设置CPSR的GE[0:3]标志(Signed arithmetic modulo 2^8 or 2^16 ,sets CPSR GE bit)。
Q:有符号饱和运算(Signed saturating arithmetic)。
SH:有符号运算,结果减半(Signed arithmetic, halving results)。
U:对2^8 or 2^16无符号求模,设置CPSR的GE[0:3]标志(Unsigned arithmetic modulo 28 or 216 ,sets CPSR GE bit)。
UQ:无符号饱和运算(Unsigned saturating arithmetic)。
UH:无符号运算,结果减半(Unsigned arithmetic ,halving results)。
GE位:GE[0]用于结果的[7:0]位,GE[1]用于结果的[15:8]位,GE[2]用于结果的[23:16]位,GE[3]用于结果的[31:24]位。
ADD8 {Cond} Rd, Rn, Rm; 以字节为单位的4个字节并行加法。Rd[31:24] = Rn[31:24] + Rm[31:24],Rd[23:16] = Rn[23:16] + Rm[23:16],Rd[15:8] = Rn[15:8] + Rm[15:8],Rd[7:0] = Rn[7:0] + Rm[7:0]。
ADD16 {Cond} Rd, Rn, Rm; 以半字为单位的2个半字并行加法。Rd[31:16] = Rn[31:16] + Rm[31:16],Rd[15:0] = Rn[15:0] + Rm[15:0]。
SUB8 {Cond} Rd, Rn, Rm; 以字节为单位的4个字节并行减法。Rd[31:24] = Rn[31:24] - Rm[31:24],Rd[23:16] = Rn[23:16] - Rm[23:16],Rd[15:8] = Rn[15:8] - Rm[15:8],Rd[7:0] = Rn[7:0] - Rm[7:0]。
SUB16 {Cond} Rd, Rn, Rm; 以半字为单位的2个半字并行减法。Rd[31:16] = Rn[31:16] - Rm[31:16],Rd[15:0] = Rn[15:0] - Rm[15:0]
ASX {Cond} Rd, Rn, Rm; 先交换Rm的半字,然后高半字相加、低半字相减。Rd[31:16] = Rn[31:16] + Rm[15:0],Rd[15:0] = Rn[15:0] - Rm[31:16]
SAX {Cond} Rd, Rn, Rm; 先交换Rm的半字,然后高半字相减、低半字相加。Rd[31:16] = Rn[31:16] - Rm[15:0],Rd[15:0] = Rn[15:0] + Rm[31:16]
USAD8 {Cond} Rd, Rn, Rm; 差值的绝对值无符号求和。Rd = Abs( Rn[31:24] - Rm[31:24] ) + Abs( Rn[23:16] - Rm[23:16] ) + Abs( Rn[15:8] - Rm[15:8] ) + Abs( Rn[7:0] - Rm[7:0] )
USADA8 {Cond} Rd, Rn, Rm, Ra; 差值的绝对值无符号求和,再累加。Rd = Ra + Abs( Rn[31:24] - Rm[31:24] ) + Abs( Rn[23:16] - Rm[23:16] ) + Abs( Rn[15:8] - Rm[15:8] ) + Abs( Rn[7:0] - Rm[7:0] )
4)、乘法算术运算指令:
MUL {S}{Cond} Rd, Rn, Rm; 乘法(Multiply), Rd = ( Rn * Rm )[31:0](如果 Rn 为 Rd,则 S 可用于 Thumb-2 中。取结果低32位)
MLA {S}{Cond} Rd, Rn, Rm, Ra; 乘加(Multiply and accumulate),Rd = ( Ra + ( Rn * Rm ) )[31:0]
MLS {S}{Cond} Rd, Rn, Rm, Ra; 乘减,Rd = ( Ra - ( Rn * Rm ) )[31:0]
UMULL{S}{Cond} RdLo, RdHi, Rn, Rm; 无符号长整数乘法(Unsigned multiply long),RdHiRdLo(64位结果) = unsigned( Rn * Rm )
UMLAL{S}{Cond} RdLo, RdHi, Rn, Rm; 无符号长整数乘加(Unsigned mul&accumulate long),RdHiRdLo = unsigned( RdHiRdLo + Rn * Rm )
UMAAL{Cond} RdLo, RdHi, Rn, Rm; 无符号长整数乘法,两次加法,RdHiRdLo = unsigned( RdHi + RdLo + Rn * Rm )
SMULL{S}{Cond} RdLo, RdHi, Rn, Rm; 有符号长整数乘法(signed multiply long),RdHiRdLo(64位结果) = signed( Rn * Rm )
SMLAL{S}{Cond} RdLo, RdHi, Rn, Rm; 有符号长整数乘加(signed mul&accumulate long),RdHiRdLo = signed( RdHiRdLo + Rn * Rm )
SMULxy{Cond} Rd, Rn, Rm; 有符号16 * 16 位乘法,Rd = signed( Rn[x] * Rm[y] ),x、y可为B(低16位)或T(高16位)。
SMLAxy{Cond} Rd, Rn, Rm, Ra; 有符号16 * 16 位乘加,Rd = signed( Ra + Rn[x] * Rm[y] ),x、y可为B(低16位)或T(高16位)。
SMLALxy{Cond} RdLo, RdHi, Rn, Rm; 有符号长整数16 * 16 位乘加,RdHiRdLo = signed( RdHiRdLo + Rn[x] * Rm[y] )。
SMULWy{Cond} Rd, Rn, Rm; 有符号32 * 16 位乘法,Rd = signed( Rn * Rm[y] )[47:16],x、y可为B(低16位)或T(高16位)。
SMLAWy{Cond} Rd, Rn, Rm, Ra; 有符号32 * 16 位乘加, Rd = signed( Ra + ( Rn * Rm[y] )[47:16] ),x、y可为B(低16位)或T(高16位)。
两次16位有符号乘法,然后乘积相加或相减、可选择先交换Rm操作数的高低半字(有X):
SMUAD{X}{Cond} Rd, Rn, Rm; Rd = signed( Rn[15:0] * RmX[15:0] ) + signed( Rn[31:16] * RsX[31:16] )
SMUSD{X}{Cond} Rd, Rn, Rm; Rd = signed( Rn[15:0] * RmX[15:0] ) - signed( Rn[31:16] * RsX[31:16] )
两次16位有符号乘法,然后乘积相加或相减、可选择先交换Rm操作数的高低半字(有X),再32位累加:
SMLAD{X}{Cond} Rd, Rn, Rm, Ra; Rd = Ra + signed( Rn[15:0] * RmX[15:0] ) + signed( Rn[31:16] * RsX[31:16] ))
SMLSD{X}{Cond} Rd, Rn, Rm, Ra; Rd = Ra + signed( Rn[15:0] * RmX[15:0] ) - signed( Rn[31:16] * RsX[31:16] ))
两次16位有符号乘法,然后乘积相加或相减、可选择先交换Rm操作数的高低半字(有X),再64位累加:
SMLALD{X}{Cond} RdLo, RdHi, Rn, Rm; RdHiRdLo = RdHiRdLo + signed( Rn[15:0] * RmX[15:0] ) + signed( Rn[31:16] * RsX[31:16] )
SMLSLD{X}{Cond} RdLo, RdHi, Rn, Rm; RdHiRdLo = RdHiRdLo + signed( Rn[15:0] * RmX[15:0] ) - signed( Rn[31:16] * RsX[31:16] )
SMMUL{R}{Cond} Rd, Rn, Rm; 有符号高位字乘法,Rd = signed( ( Rn * Rm )[63:32] ),有R则对结果进行舍入、否则截断。
SMMLA{R}{Cond} Rd, Rn, Rm, Ra; 有符号高位字乘加,Rd = signed( Ra + ( Rn * Rm )[63:32] ),有R则对结果进行舍入、否则截断。
SMMLS{R}{Cond} Rd, Rn, Rm, Ra; 有符号高位字乘减,Rd = signed( Ra - ( Rn * Rm )[63:32] ),有R则对结果进行舍入、否则截断。
5)、有符号或无符号除法算术运算指令:Opcode为 SDIV(有符号)或 UDIV(无符号)。
SDIV{Cond} Rd, Rn, Rm; Rd = Rn / Rm ,PC、SP不可用于Rd、Rn、Rm。
UDIV{Cond} Rd, Rn, Rm; Rd = Rn / Rm ,PC、SP不可用于Rd、Rn、Rm。
SEL{Cond} Rd, Rn, Rm; 选择字节。如果 GE[0] = 1,则 Rd[7:0] = Rn[7:0],否则 Rd[7:0] = Rm[7:0];GE[1]、GE[2]、GE[3] 时位 [15:8]、[23:16]、[31:24] 的选择方法与 GE[0] 相似。
6)、逻辑运算:
Opcode {S}{Cond} Rd, Rn, Operand2; Rd = Rn Opcode Operand2
Opcode:AND,ORR,EOR,BIC(OR NOT),ORN(OR NOT)。
AND{S}{Cond} Rd, Rn, Operand2; 逻辑“与”,Rd = Rn AND Operand2。
ORR{S}{Cond} Rd, Rn, Operand2; 逻辑“或”,Rd = Rn ORR Operand2。
EOR{Cond} Rd, Rn, Operand2; Exclusive OR、逻辑“异或”,Rd = Rn EOR Operand2。
BIC{Cond} Rd, Rn, Operand2; Bit clear、位清除,逻辑“与非”,Rd = Rn AND NOT Operand2。
ORN{Cond} Rd, Rn, Operand2; 逻辑“或非”、仅T32,Rd = Rn OR NOT Operand2。
7)、比较测试:Opcode {Cond} Rn, Operand2;
更新 Rn Opcode Operand2 的 CPSR 标记。
Opcode:-,+,AND,EOR。
CMP{Cond} Rn, Operand2; 比较(Compare),更新Rn - Operand2的CPSR的标志位。
CMN{Cond} Rn, Operand2; 负数比较(Compare negative),更新Rn + Operand2的CPSR标志位。
TST{Cond} Rn, Operand2; 位测试(bit test),更新Rn AND Operand2的CPSR的标志位。
TEQ{Cond} Rn, Operand2; 相等测试(Test equivalence),更新Rn EOR Operand2的CPSR的标志位。
8)、反转、前导0:Opcode {Cond} Rd, Rm;
Opcode:REV(32位大小端转换),REV16(16位大小端转换),REVSH(16位带符号扩展大小端转换)。
REV{Cond} Rd, Rm; 反转(reverse)字中的字节,Rd[31:24] = Rm[7:0],Rd[23:16] = Rm[15:8],Rd[15:8] = Rm[23:16],Rd[7:0] = Rm[31:24]
REV16{Cond} Rd, Rm; 反转两个半字中的字节,Rd[15:8] = Rm[7:0],Rd[7:0] = Rm[15:8],Rd[31:24] = Rm[23:16],Rd[23:16] = Rm[31:24]
REVSH{Cond} Rd, Rm; 反转低半字中的字节、并符号扩展,Rd[15:8] = Rm[7:0],Rd[7:0] = Rm[15:8],Rd[31:16] = Rd[15] * &FFFF
RBIT{Cond} Rd, Rm; 反转32位字的位顺序,For (i = 0; i < 32; i++) ; Rd[i] = Rm[31- i]。
CLZ{Cond} Rd, Rm; 从最高位起计算前导零数目(Count left zero),Rd = Rm 中的前导零的数目。
9)、移动数据:Opcode {S}{Cond} Rd, Operand2; Opcode为MOV(移动MOVE)、MVN(求反移动)、MOVT(移到顶部)
MOV{S}{Cond} Rd, Operand2; Rd = Operand2
MVN{S}{Cond} Rd, Operand2; Rd = NOT Operand2
MOVT{Cond} Rd, #imm16; Rd[31:16] = imm16,Rd[15:0] 不受影响,imm16 的范围为 0-65535
MOV{Cond} Rd, #imm16; Rd[15:0] = imm16,Rd[31:16] = 0,imm16 范围为 0-65535
10)、移位:
Opcode {S}{Cond} {Rd,} Rm{, Rs|#sh}; Rd = Opcode(Rm{, Rs|#sh})、等同于MOV{S}{Cond} Rd, Operand2; 的对应指令。
Opcode:ASR、LSR、LSL、ROR、RRX。结果不写Rd时,等效于计算Operand2、或说是对Rm寄存器进行移位操作。对Rm寄存器进行移位,除RRX按顺序循环右移一位外,其它Op的移位量n为寄存器Rs(只用最低有效字节)或立即数sh(移位次数为5位二进制),进位标志会根据寄存器Rm最后一位被移除掉的位的值bit[n-1]进行更新。
ASR(Arithmetic shift right):Rm寄存器算术右移或说是带符号位的右移(符号位是bit[31],符号位拷贝到空位)。
ASR{S}{Cond} Rd, Rm, Rs|#sh; Rd = ASR(Rm, Rs|#sh),与 MOV{S} Rd, Rm, ASR Rs|#sh; 等效。
LSR(Logical shift right):Rm寄存器逻辑右移或者说是无符号的右移(空位清0)。
LSR{S}{Cond} Rd, Rm, Rs|#sh; Rd = LSR(Rm, Rs|#sh),与MOV{S}{Cond} Rd, Rm, LSR Rs|#sh; 等效。
LSL(Logical shift left):Rm寄存器逻辑左移(空位清0)。
LSL{S}{Cond} Rd, Rm, Rs|#sh; Rd = LSL(Rm, Rs|#sh),与 MOV{S}{Cond} Rd, Rm, LSL Rs|#sh; 等效。
ROR(Rotate right):Rm寄存器循环右移。
ROR{S}{Cond} Rd, Rm, Rs|#sh; Rd = ROR(Rm, Rs|#sh),与 MOV{S}{Cond} Rd, Rm, ROR Rs|#sh; 等效。
RRX(Rotate right with extend):Rm寄存器带进位扩展的循环右移。RRX参与循环右移的总共有33位,即32位的Rm+进位标志位。但是RRX只按顺序循环右移一位,也就是bit[0]移动到进位标志位,进位标志位循环移动到bit[31],其他位按顺序右移一位。
RRX{S}{Cond} Rd, Rm; Rd = RRX(Rm), 与 MOV{S}{Cond} Rd, Rm, RRX; 等效。
11)、位域操作:
lsb最低有效位,width连续位数,width + lsb 必须小于32。
BFC{Cond} Rd, #lsb, #width; 位域清零,Rd[( width + lsb - 1 ):lsb] = 0,Rd 的其他位不受影响。
BFI{Cond} Rd, Rn, #lsb, #width; 位域插入,Rd[( width + lsb - 1 ):lsb] = Rn[( width - 1 ):0],Rd 的其他位不受影响。
SBFX{Cond} Rd, Rn, #lsb, #width; 有符号位域提取,Rd[( width - 1 ):0] = Rn[( width + lsb - 1 ):lsb],Rd[31:width] = 复制 (Rn[width+lsb-1])。
UBFX{Cond} Rd, Rn, #lsb, #width; 无符号位域提取,Rd[( width - 1 ):0] = Rn[( width + lsb - 1 ):lsb],Rd[31:width] = 复制 ( 0 )。
PKHBT{Cond} Rd, Rn, Rm{, LSL #sh}; 组合:低半字 + 高半字:Rd[15:0] = Rn[15:0],Rd[31:16] = (Rm LSL #sh)[31:16]。sh 的范围为 0-31。
PKHTB{Cond} Rd, Rn, Rm{, ASR #sh}; 组合:高半字 + 低半字:Rd[31:16] = Rn[31:16],Rd[15:0] = (Rm ASR#sh)[15:0]。sh 的范围为 1-32。
12)、符号扩展操作:rotation = ROR #sh,sh 的范围为 0-3。
SXTH Rd, Rm{, rotation}; 有符号扩展、半字到字,Rd[31:0] = SignExtend( ( Rm ROR (8 * sh) )[15:0] )。
SXTB16 Rd, Rm{, rotation}; 有符号扩展、两个字节到半字,Rd[31:16] = SignExtend( ( Rm ROR (8 * sh) )[23:16] ),Rd[15:0] = SignExtend( ( Rm ROR (8 * sh) )[7:0] )。
SXTB Rd, Rm{, rotation}; 有符号扩展、字节到字,Rd[31:0] = SignExtend( ( Rm ROR (8 * sh) )[7:0] )。
UXTH Rd, Rm{, rotation}; 无符号扩展、半字到字,Rd[31:0] = ZeroExtend( ( Rm ROR (8 * sh) )[15:0] )。
UXTB16 Rd, Rm{, rotation}; 无符号扩展、两个字节到半字,Rd[31:16] = ZeroExtend( ( Rm ROR (8 * sh) )[23:16] ),Rd[15:0] = ZeroExtend( ( Rm ROR (8 * sh) )[7:0] )。
UXTB Rd, Rm{, rotation}; 无符号扩展、字节到字,Rd[31:0] = ZeroExtend( ( Rm ROR (8 * sh) )[7:0] )。
带加法的有符号扩展:
SXTAH Rd, Rn, Rm{, ROR #sh}; 半字到字、加法,Rd[31:0] = Rn[31:0] + SignExtend( ( Rm ROR (8 * sh) )[15:0] )。
SXTAB16 Rd, Rn, Rm{, ROR #sh}; 两个字节到半字、加法, Rd[31:16] = Rn[31:16] + SignExtend( ( Rm ROR (8 * sh) )[23:16] ),Rd[15:0] = Rn[15:0] + SignExtend( ( Rm ROR (8 * sh) )[7:0] )。
SXTAB Rd, Rn, Rm{, ROR #sh}; 字节到字,加法,Rd[31:0] = Rn[31:0] + SignExtend((Rm ROR (8 * sh))[7:0])。
带加法的无符号扩展:
UXTAH Rd, Rn, Rm{, ROR #sh}; 半字到字、加法,Rd[31:0] = Rn[31:0] + ZeroExtend( ( Rm ROR (8 * sh) )[15:0] )。
UXTAB16 Rd, Rn, Rm{, ROR #sh}; 两个字节到半字、加法, Rd[31:16] = Rn[31:16] + ZeroExtend( ( Rm ROR (8 * sh) )[23:16] ),Rd[15:0] = Rn[15:0] + ZeroExtend( ( Rm ROR (8 * sh) )[7:0] )。
UXTAB Rd, Rn, Rm{, ROR #sh}; 字节到字,加法,Rd[31:0] = Rn[31:0] + ZeroExtend((Rm ROR (8 * sh))[7:0])。
Opcode {Cond} Label; Opcode {Cond} Rm;
条件{Cond}跳转除B指令外,通常只有ARM可用。
B Label; 跳转(Branch),程序无条件跳转到标号Label处执行。PC = label,label 的跳转范围:ARM:±32MB,T16: ±2KB,T32: ±16MB。
B{Cond} label; 程序条件跳转到标号Label处执行。label 的跳转范围:ARM:±32MB,T16: -252 - +256B,T32:±1MB。
BL Label; 带链接的跳转BL(Branch with Link), 当程序无条件跳转到标号Label处执行时,同时将当前的PC值保存到R14中。LR = 下一指令的地址,PC = label。label的跳转范围:ARM:±32MB,T16: ±4MB,T32: ±16MB 。
BL{Cond} label; 带链接的条件跳转,label的跳转范围:ARM:±32MB。
BX Rm; 跳转并交换BX(Branch and exchange), 跳转到指令中所指定的目标地址,目标地址处的指令既可以是ARM指令,也可以是Thumb指令。PC = Rm。 如果 Rm[0] 为 1,目标为 Thumb;如果 Rm[0] 为 0,目标则为 ARM。“交换”指ARM和Thumb处理器指令状态交换。
BLX Rm; 带链接跳转并交换BLX(Branch with Link and exchange), 跳转到指令中所指定的目标地址,目标地址处的指令既可以是ARM指令,也可以是Thumb指令。PC = Rm[31:1]。 如果 Rm[0] 为 1,目标为 Thumb;如果 Rm[0] 为 0,目标则为 ARM。
BLX label; LR = 下一指令的地址,PC = label,更改指令集。label 的跳转范围:ARM:±32MB,T16: ±4MB,T32: ±16MB。
CB{N}Z label; 比较,如果为(非)零,则跳转(Compare 0{N0} Branch)。如果 Rn {== 或 !=} 0,则 PC = label。label 的跳转范围4--130B。
TBB [Rn, Rm]; 表跳转字节TBB(Table Branch Byte ), PC+ = Rn[Rm]*2。PC = PC + ZeroExtend( Memory( Rn + Rm, 1) << 1)。 跳转范围为 4--514。 Rn 可为 PC。在这里,Rn 指向跳转表的基址,Rm 则给出表(数组)中元素的下标。
TBB [Rn, Rm, LSL #1]; 表跳转半字TBH(Table Branch Halfword ), PC+ = Rn[Rm*2]*2或说PC = PC + ZeroExtend( Memory( Rn + Rm<< 1, 2) << 1)。 跳转范围为 4--131072(128KB+2), Rn 可为 PC。在这里,Rn 指向跳转表的基址,Rm 则给出表(数组)中元素的下标。
因为 CM3 的指令至少是按半字对齐的,表中的数值都是在左移一位后才作为前向跳转的偏移量的。
又因为 PC 的值为当前地址+4,故 TBB 的跳转范围可达 255*2+4=514;TBH 的跳转范围更可高达
65535*2+4 =128KB+2。请注意:Both TBB 和 TBH 都只能作前向跳转,也就是说偏移量
是一个无符号整数。
BKPT(breakpoint):断点,BKPT #immed; 预取中止或进入调试状态。 ARM指令中immed编码为 16 位的位域,T16为8位值。
SVC(Supervisor call):超级用户调用异常,SVC {Cond} #immed; ARM指令中immed编码为 24 位的位域,T16为8位值。 以前为 SWI。
SMC(Secure Monitor Call):安全监控调用,SMC {Cond} #imm16; 指令中编码为 16 位的位域。 以前为 SMI。
MRS(Move PSR to register):程序状态寄存器到通用寄存器的数据传送指令,MRS {Cond} Rd, PSR; Rd = PSR。
MSR(Move register or #imm8 to PSR):通用寄存器或8位立即数到程序状态寄存器指定位段的数据传送指令,
MSR {Cond} PSR_fields, Rm|#imm8; PSR = Rm(仅选字节)|#imm8。
CPS(Change PE State ):改变处理器模式,CPS #p_mode;
CPSID iflags {, #p_mode}; 禁用指定的中断,可选择更改模式。iflags:中断标记。 一个或多个 a、i、f(中止、中断、快速中断)。
CPSIE iflags {, #p_mode}; 启用指定的中断,可选择更改模式。
SETEND endianness; 设置端序,为加载和保存设置端序。endianness 可为 BE(大端)或 LE(小端)。
NOP{Cond}; 无操作,可能不花费任何时间。
SEV{Cond}; 设置事件,向多处理器发送事件信号。 如不执行,为 NOP。
WFE {Cond}; 等待事件,IRQ、FIQ、不精确的中止或调试进入请求。 如果不执行,则为 NOP。
WFI {Cond}; 等待IRQ、FIQ不精确中止或调试进入请求。不执行,为NOP
YIELD {Cond}; 生成对其他线程的控制。 如果不执行,则为 NOP。
DBG{Cond} {#Option}; 调试提示,向调试系统及其相关系统发送提示。Option:对提示操作的可选限制。
DMB{Cond} {Option}; 数据内存屏障,确保内存访问的观察顺序。
DSB{Cond} {Option}; 数据同步屏障,确保内存访问完成。
ISB{Cond} {Option}; 指令同步屏障,刷新处理器管道并跳转预测逻辑。
1)、加载或存储字、字节、半字、双字。LDR(from memory Load to Register),STR(from Register Store To memory)。
size:B(无符号字节、加载时零扩展为32位),SB(有符号字节、仅LDR,符号扩展为32位),H(无符号半字、加载时零扩展为32位),SH(有符号半字、仅LDR,符号扩展为32位),-(如果是字,则省略)。
T:如果有 T,则带有用户模式特权。
offset:ARM字或字节±4095,其它±255。T32双字±1020,其它±255。
!:在数据传送前,Rn + offset的结果作为传送地址,若使用后缀“!”,则结果回写到Rn。
Opcode{size}{Cond}{T} Rd, [Rn{, #offset}]; 立即数偏移,Opcode为LDR,Rd= [Rn + offset](size) ;为STR,[Rn + offset](size)= Rd。
Opcode{size}{Cond} Rd, [Rn, #offset]!; 前索引立即数偏移。Rn = Rn + offset,Opcode为LDR,Rd= [Rn](size) ;为STR,[Rn](size)= Rd。
Opcode{size}{Cond}{T} Rd, [Rn], #offset ; 后索引立即数偏移。Opcode为LDR,Rd= [Rn](size) ;为STR,[Rn](size)= Rd;Rn = Rn + offset。
Opcode{size}{Cond} Rd, [Rn, ±Rm {, shift}];寄存器偏移。Opcode为LDR,Rd = [Rn ±Rm {, shift}](size) ;为STR,[Rn ±Rm {, shift}](size) = Rd。
Opcode{size}{Cond} Rd, [Rn, ±Rm {, shift}]!; 前索引寄存器偏移。Rn= Rn ±Rm{, shift},Opcode为LDR,Rd= [Rn](size);为STR,[Rn](size)= Rd
Opcode{size}{Cond}{T} Rd, [Rn], ±Rm {, shift} ; 后索引寄存器偏移。Op为LDR,Rd= [Rn](size);为STR,[Rn](size)= Rd;Rn = Rn ±Rm {, shift}。
LDR{size}{Cond} Rd, label; 地址为PC加偏移量。Rd = [label](size)。
LDRD{Cond} Rd1, Rd2, label; 地址为PC加偏移量的双字加载或存储。Rd1 = [label],Rd1 = [label + 4]。
OpD{Cond} Rd1, Rd2, [Rn{, #offset}]; 立即数偏移的双字加载或存储。OpD为LDR,Rd1 =[Rn + offset],Rd2= [Rn + offset + 4];OpD为STR,[Rn + offset] = Rd1,[Rn + offset + 4] = Rd2。
OpD{Cond} Rd1, Rd2, [Rn, #offset]!; 前索引立即数偏移的双字加载或存储。Rn = Rn + offset,OpD为LDR,Rd1 = [Rn],Rd2 = [Rn+4];OpD为STR,[Rn] = Rd1,[Rn + 4] = Rd2。
OpD{Cond} Rd1, Rd2, [Rn], #offset ; 后索引立即数偏移的双字加载或存储。Opcode为LDR,Rd1 = [Rn] ,Rd2 = [Rn + 4];OpD为STR,[Rn] = Rd1,[Rn + 4] = Rd2;Rn = Rn + offset。
OpD{Cond} Rd1, Rd2, [Rn, ±Rm {, shift}];寄存器偏移的双字加载或存储。OpD为LDR,Rd1 = [Rn ±Rm {, shift}],Rd2 = [Rn ±Rm {, shift} + 4];OpD为STR,[Rn ±Rm {, shift}] = Rd1,[Rn ±Rm {, shift} + 4] = Rd2。
OpD{Cond} Rd1, Rd2, [Rn, ±Rm {, shift}]!; 前索引寄存器偏移的双字加载或存储。Rn= Rn ±Rm{, shift},OpD为LDR,Rd1 = [Rn],Rd2 = [Rn + 4];OpD为STR,[Rn] = Rd1,[Rn + 4] = Rd2。
OpD{Cond} Rd1, Rd2, [Rn], ±Rm {, shift} ; 后索引寄存器偏移的双字加载或存储。OpD为LDR,Rd1 = [Rn],Rd2 = [Rn + 4];OpD为STR,[Rn] = Rd1,[Rn + 4] = Rd2;Rn = Rn ±Rm {, shift}。
ADR Rd, label; PC 相对的寻址,Rd = label。 {B}{Cond} Rd, Rt, [Rn]; 交换字或字节。交换字:temp = [Rn],[Rn] = Rt,Rd = temp。交换字节:temp = ZeroExtend([Rn][7:0]),[Rn][7:0] = Rm[7:0],Rd = temp。
2)、预载数据或指令:
Opcode = PLD(Preload Data),= PLI(Preload Instruction)
处理器可向内存系统发信号,说明不久后要从某个地址加载数据或指令。
Opcode{Cond} [Rn {, #offset}];
Opcode{Cond} [Rn, ±Rm {, shift}];
Opcode{Cond} label;
3)、加载或存储多个寄存器:Opcode = LDM( Load Multiple)加载多个寄存器,= STM(Store Multiple )存储多个寄存器。
IA(Increase After传送后增加):每次传送后增大地址(这是缺省情形,可以省略)。
IB(Increase Before传送前增加):每次传送前增大地址(仅ARM)。
DA(Decrease After传送后减小):每次传送后减小地址(仅ARM)。
DB(Decrease Before传送前减小):每次传送前减小。
Rn:基址寄存器。reglist{^}:一个或多个的寄存器列表,在大刮号内。
!:若使用后缀“!”,则最终地址回写到Rn。
Opcode{IA|IB|DA|DB}{Cond} Rn{!}, reglist{^}; 加载或存储多个寄存器。对于LDM,如reglist{^}包含PC,则跳转、且CPSR = SPSR,仅限异常模式。
POP{Cond} reglist{^}; 等效于LDMIA{Cond} SP!, reglist{^};
PUSH{Cond} reglist{^}; 等效于SDMDB{Cond} SP!, reglist{^};
RFE{IA|IB|DA|DB}{Cond} Rn{!}; 从异常中返回。PC = [Rn],CPSR = [Rn + 4] 。
SRS{IA|IB|DA|DB} {Cond} SP{!}, #p_mode; 存储返回状态。p_mode指定模式编号,[SPm] = LR,[SPm + 4] = CPSR
4)、加载或存储独占:
LDREX{Cond} Rd, [Rn{, #offset}]; Rd = [Rn + offset],将地址标记为独占访问。 如不是共享地址,则为突出显示标记设置,Rd、Rn 不可为 PC。
LDREX{H|B}{Cond} Rd, [Rn]; 半字或字节独占加载。Rd[15:0] = [Rn] 或 Rd[7:0] = [Rn],将地址标记为独占访问。如果不是共享地址,则为突出显示的标记设置。 Rd、Rn 不可为 PC。
LDREXD Rd1, Rd2, [Rn]; 双字独占加载。 Rd1 = [Rn],Rd2 = [Rn+4],将地址标记为独占访问。如果不是共享地址,则为突出显示的标记设置。 Rd1、Rd2、Rn 不可为 PC。
STREX{Cond} Rd, Rt, [Rn{, #offset}]; 如果允许,则 [Rn + offset] = Rt,清除独占标记,Rd = 0。 否则 Rd = 1。Rd、Rm、Rn 不可为 PC。
STREX{H|B}{Cond} Rd, Rt, [Rn]; 半字或字节独占存储。如果允许,则 [Rn] = Rt[15:0] 或 [Rn] = Rt[7:0],清除独占标记,Rd = 0。 否则 Rd = 1。Rd、Rt、Rn 不可为 PC。
STREXD Rd, Rt1, Rt2, [Rn]; 双字独占存储。 如果允许,则 [Rn] = Rt1,[Rn+4] = Rt2,清除独占标记,Rd = 0。 否则 Rd = 1。Rd、Rt1、Rt2、Rn 不可为 PC。
CLREX; 清除独占。清除局部处理器独占标记。
一个CPU核最少包含系统指令、跳转指令、ALU指令和存储访问单元SAU指令。ARM的系统指令数太多,不利于使用汇编语言。如果对特殊功能寄存器(程序状态寄存器PSR(包含应用程序 APSR、中断号 IPSR、执行 EPSR),系统控制寄存器CONTROL)的访问也归于使用ALU指令的MOV等、就完美了。MRS程序状态寄存器到通用寄存器的数据传送指令,MSR通用寄存器或8位立即数到程序状态寄存器指定位段的数据传送指令,CPS改变处理器模式,CPSID禁用指定的中断,CPSIE启用指定的中断、等等,都归于对状态寄存器PSR的位或位段操作;SETEND设置端序、为加载和保存设置端序,SEV设置事件、向多处理器系统发送事件信号,WFE等待事件,WFI 等待 IRQ、FIQ、不精确的中止或调试进入请求,YIELD生成对其他线程的控制,DBG调试提示、向调试系统及其相关系统发送提示,DMB数据内存屏障、确保内存访问的观察顺序,DSB数据同步屏障,确保内存访问完成,ISB指令同步屏障、刷新处理器管道并跳转预测逻辑、等等,都归于对系统控制寄存器CONTROL的位或位段操作。如果再将以下3条指令归类到跳转指令类:BKPT断点,BKPT #immed; 预取中止或进入调试状态;SVC超级用户调用异常,
SVC {Cond} #immed; SMC安全监控调用,SMC {Cond} #imm16; 指令中编码为 16 位的位域, 以前为 SMI;那么,ARM汇编语言就会很简洁,只有6 + 9 + 18 = 33条指令束(包含跳转指令、ALU指令和SAU指令)。
1、跳转指令类型:Opcode {Cond} Label; Opcode {Cond} Rm;
B{Cond} label; (无)条件跳转(ARM:±32MB,T16: -252 - +256B,T32:±1MB)。
B{L}{X}{Cond} label|Rm; (无)条件带链接(交换)的跳转(ARM:±32MB)。
TB [Rn, Rm]; 表跳转字节或半字。在这里,Rn 指向跳转表的基址,Rm 则给出表(数组)中元素的下标。
BKPT(breakpoint):断点,BKPT #immed; 预取中止或进入调试状态。 ARM指令中immed编码为 16 位的位域,T16为8位值。
SVC(Supervisor call):超级用户调用异常,SVC {Cond} #immed; ARM指令中immed编码为 24 位的位域,T16为8位值。 以前为 SWI。
SMC(Secure Monitor Call):安全监控调用,SMC {Cond} #imm16; 指令中编码为 16 位的位域。 以前为 SMI。
2、存储器访问指令类型:存储访问单元SAU(Storage access unit)。
加载或存储独占的指令为需要实现对存储器访问的“读-修改-写”情形下的原子操作(无需关中断实现),LDREX指令(独占和读内存到寄存器),ALU的寄存器“修改”指令,STREX指令(清独占和修改后的内容写到内存)。
1)、加载或存储字、字节、半字、双字。LDR(from memory Load to Register),STR(from Register Store To memory)
2)、预载数据或指令:
Opcode = PLD(Preload Data),= PLI(Preload Instruction)
4)、加载或存储独占:LDREX(Load Register Exclusive),
STREX(Store Register Exclusive)
LDR{D}{size}{Cond}{T} Rd, {[Rn], Operand2}{[Rn{, Operand2}]}{!};
STR{D}{size}{Cond}{T} Rd, {[Rn], Operand2}{[Rn{, Operand2}]}{!};
PLD{Cond} [Rn {, Operand2}];
PLD{Cond} label;
PLI{Cond} [Rn {, Operand2}];
PLI{Cond} label;
LDREX{D}{H|B}{Cond} Rd, {Rt1}, {Rt2}, [Rn]|[Rn{, #offset}];
STREX{D}{H|B}{Cond} Rd, {Rt1}, {Rt2}, [Rn]|[Rn{, #offset}];
CLREX; 清除独占,清除局部处理器独占标记。
3、算术逻辑单元ALU(Arithmetic Logical Unit)
编写操作系统,很少使用有(无)符号相关的指令、或说不用带“符号位”的操作数。ALU单元的指令数也就16条,加减、逻辑、MOV;使用补码逻辑,减法运算等效于加法运算。ALU的指令写法:
Opcode {S}{Cond} {Rd}, Rn, Operand2; Rd = Rn Opcode Operand2。
正数的补码是自身,负数的补码是“取反加1”。
SUB{S}{Cond} {Rd}, Rn, Operand2; Rd = [Rn]补 + [- Operand2]补,或说减法等于加[- Operand2]的补码。RSB逆向减法也就是Rd = [- Rn]补 + [Operand2]补,CMP(Compare)比较指令等、只是不将结果存到Rd。
ADD{S}{Cond} Rd, Rn, Operand2; Rd = Rn + Operand2,加法。
ADC{S}{Cond} Rd, Rn, Operand2; Rd = Rn + Operand2 + C,带进位加法。
SUB{S}{Cond} Rd, Rn, Operand2; Rd = Rn + [- Operand2]补,减法。
SBC{S}{Cond} Rd, Rn, Operand2; Rd = Rn + [- Operand2]补 - !C,带进位减法。
RSB{S}{Cond} Rd, Rn, Operand2; Rd = [- Rn]补 + Operand2,逆向减法。
RSC{S}{Cond} Rd, Rn, Operand2; Rd = [- Rn]补 + Operand2 - !C,带进位逆向减法。
CMN{Cond} Rn, Operand2; Rn + Operand2,与负数比较(负负为正)、根据结果设置CPSR的标志位。
CMP{Cond} Rn, Operand2; Rn + [- Operand2]补,比较、根据结果设置CPSR的标志位。
AND{S}{Cond} Rd, Rn, Operand2; Rd = Rn AND Operand2,按位“与”。
ORR{S}{Cond} Rd, Rn, Operand2; Rd = Rn OR Operand2,按位“或”。
EOR{S}{Cond} Rd, Rn, Operand2; Rd = Rn EOR Operand2,按位“异或”。
BIC{S}{Cond} Rd, Rn, Operand2; Rd = Rn AND NOT Operand2,按位“与非”。
ORN{S}{Cond} Rd, Rn, Operand2; Rd = Rn OR NOT Operand2,按位“或非”。
TST{Cond} Rn, Operand2; Rn AND Operand2,位测试、并根据结果设置CPSR的标志位。
TEQ{Cond} Rn, Operand2; Rn EOR Operand2,相等测试、并根据结果设置CPSR的标志位。
MOV{S}{Cond} Rd, Operand2;
MOV指令没有使用Rn,理论上可以有32个变种MOV指令。如果不使用Cond条件码,就可以多出4位二进制编码、可用于寻址32个寄存器,或说Rd、 Rn、Rm、Rs的寄存器寻址到32个,其中就会包含PSR和CONTROL寄存器;这样一来,就可取消系统指令组、将其包含到ALU指令组中。可惜的是ARM并没有这样走,要不ARM汇编语言将大放异彩。
MOV{S}{Cond} Rd, Rm{,shift}; Rd = Rm{,shift}。
MVN{S}{Cond} Rd, Rm{,shift}; Rd = NOT Rm{,shift}。
MOVT{Cond} Rd, #imm16; Rd[31:16] = imm16,Rd[15:0] 不受影响,imm16 的范围为 0-65535
MOV{Cond} Rd, #imm16; Rd[15:0] = imm16,Rd[31:16] = 0,imm16 范围为 0-65535
位域清零:BFC{Cond} Rd, #lsb, #width; Rd[ ( width + lsb - 1 ):lsb ] = 0,Rd 的其他位不受影响。
位域插入:BFI{Cond} Rd, Rn, #lsb, #width; Rd[ ( width + lsb - 1 ):lsb ] = Rn[ ( width - 1 ):0 ],Rd 的其他位不受影响。
4、可伸缩向量运算单元SVCU(Scalable Vector calculations Unit):
向量操作类指令(可伸缩向量SVE指令集)包含:单指令多数据并行SIMD向量(vectormode)运算(Single-Instruction Multiple-Data)和标量floating-point(浮点)运算,基本的数字信号处理DSP(digital signal processing)指令集。
可伸缩向量单元SVU(Scalable Vector Unit):去除DSP、VFP的简化型SVCU(大幅缩减逻辑门数量),只有一些简单的SIMD向量整形操作指令;主要应用于存储访问的空间管理,如求256字节向量的最大值字节指令VMAX256和2K位图的从最高位起计算前导零数目指令VCLZ2K。假如有最大64K个不同优先级字节值(数值越大优先级越高)的进程调度,可按16位进程号分为256个组;当一个进程就绪或挂起等等情形时,必须对该进程所对应的组执行一条指令VMAX256,从而输出该组的优先级最大字节值;之后对256组再一次VMAX256得到MMAX,如果当前进程的优先级字节值小于MMAX,则置“需调度”标志,这样编写操作系统调度程序就非常简洁了。空间分配算法为“四方兽空间分配算法,青龙粒、白虎骨,朱雀来、玄武出。”,包含单粒位图分配算法和“独狼空间连续粒度”分配算法。而常用的2K或64K单粒位图分配算法必须使用到“从最高位起计算前导零数目指令VCLZ2K”,64K 位图需循环32次指令VCLZ2K,而最终实现程序就几条指令吧。
关于移位的相关指令已经在Operand2和MOV指令实现了,可以忽略。33条基本指令外的其它指令,如DSP、并行加减算术运算、等等,应该放入SVCU单元来实现。
设想的高级电脑5大核CPU如下:通过矩阵总线开关切换SAU、应用DMA。
1)、进程(线程)大核结构:9xALU + SAU + SVU。可以同时并行一次8个进程(线程)运行。包含时间管理员(8xALU调度)和空间管理员程序(1个ALU)、操作系统的主要程序等等。(心脏和大脑)
2)、通信管理员大核结构:2xALU + SAU + SVCU。用于Internet网络通信、ALU + SVCU(网络视音频),另一个ALU用于其它通讯管理。
3)、超清视音频管理员大核结构:2xALU + SAU + 16xSVCU。1个ALU为音频管理、1个ALU为视频管理,共用16个SVCU实现超清视音频并行运算。
4)、界面交流管理员大核结构:2xALU + SAU + SVCU。人机交流(自然语言处理等),“感觉”输入处理。
5)、字典、联想、经验、思考、推理、生长发育等等管理员大核结构:5xALU + SAU + SVCU。操作系统内部线程(心脏和大脑)。
如果要按照自己设想去玩5大核CPU,又需要花费大量时间去学习和应用FPGA。那、学习唱歌的时间还有吗?要知道我花了3年半时间去学习唱歌,不可能半途而废吧。看来还是得按原计划、一年后逐步回归“学唱歌”事业,这类产品项目只能是慢慢弄。
附录:
Thumb‐2指令集(网上择抄)
当BIT15:11 = 0b111xx,xx非00时、为32位指令,其它情形为16位指令。63条类、16位指令,
表二:按指令机器码升序排列(v is immed_value,n is Rn,m is Rm,s is Rs,r is register_list,c is condition,h低寄存器范围:R0–R7)。
0000 0vvv vvmm mnnn -- LSL{S} Rd,Rm,#immed_5 // 逻辑左移(空位清0),移位次数为5位立即数值,{S}NZC。Rd = Rm<{S} Rd,Rm,#immed_5 // 逻辑右移(空位清0),移位次数为5位立即数值,{S}NZC。Rd = Rm>>immed_5。
0001 0vvv vvmm mddd -- ASR{S} Rd,Rm,#immed_5// 算术右移(符号位拷贝到空位),移位次数为5位立即数值,{S}NZC。Rd = Rm>>immed_5
0001 100m mmnn nddd -- ADD{S} Rd,Rn,Rm // 加法运算。Rd = Rn + Rm,{S}NZCV。
0001 101m mmnn nddd -- SUB{S} Rd,Rn,Rm // 减法运算。Rd = Rn - Rm,{S}NZCV。
0001 110v vvnn nddd -- ADD{S} Rd,Rn,#immed_3 // 加法运算。Rd = Rn + immed_3,{S}NZCV。
0001 111v vvnn nddd -- SUB{S} Rd,Rn,#immed_3 // 减法运算。Rd = Rn - immed_3,{S}NZCV。
0001 1100 00nn nddd -- MOV Rd,Rn // 寄存器数据传送。Rd = Rn 。
0010 0ddd vvvv vvvv -- MOV Rd,#immed_8 // 立即数据传送。Rd = immed_8 。
0010 1nnn vvvv vvvv -- CMP{S} Rn,#immed_8 // 比较刷新{S}。Rn - immed_8 -->{S}NZCV。
0011 0ddd vvvv vvvv -- ADD{S} Rd,#immed_8 // 加法运算。Rd = Rd + immed_8,{S}NZCV。
0011 1ddd vvvv vvvv -- SUB{S} Rd,#immed_8 // 减法运算。Rd = Rd - immed_3,{S}NZCV。
0100 0000 00mm mddd -- AND{S} Rd,Rm // 逻辑与运算。Rd = Rd & Rm,{S}NZ。
0100 0000 01mm mddd -- EOR{S} Rd,Rm // 逻辑异或运算。Rd = Rd ^ Rm,{S}NZ。
0100 0000 10ss sddd -- LSL{S} Rd,Rs // 逻辑左移(空位清0),移位次数为Rs数值,{S}NZC。Rd = Rd<{S} Rd,Rs // 逻辑右移(空位清0),移位次数为Rs数值,{S}NZC。Rd = Rd>>Rs。
0100 0001 00ss sddd -- ASR{S} Rd,Rs // 算术右移(符号位拷贝到空位),移位次数为Rs数值,{S}NZC。Rd = Rd>>Rs
0100 0001 01mm mddd -- ADC{S} Rd,Rm // 带进位加法运算。Rd = Rd + Rm + Carry,{S}NZCV。
0100 0001 10mm mddd -- SBC{S} Rd,Rm // 带进位减法运算。Rd = Rd - Rm - NOT(Carry),{S}NZCV。
0100 0001 11ss sddd -- ROR{S} Rd,Rs // 循环右移,移位次数为Rs数值,{S}NZC。Rd = Rd循环右移Rs位。
0100 0010 00mm mnnn -- TST{S} Rn,Rm // 位测试刷新{S}。 Rn & Rm-->{S}NZCV。
0100 0010 01mm mddd -- NEG{S} Rd,Rm // 数据取反。 Rd = - Rm,{S}NZCV。
0100 0011 00mm mddd -- ORR{S} Rd,Rm // 逻辑或运算。Rd = Rd | Rm,{S}NZ。
0100 0010 10mm mnnn -- CMP{S} Rn,Rm // 比较刷新{S}。Rn - Rm -->{S}NZCV。
0100 0010 11mm mnnn -- CMN{S} Rn,Rm // 负数比较刷新{S}。Rn + Rm -->{S}NZCV。(把一个数跟另一个数据的二进制补码相比较)
0100 0011 01mm mddd -- MUL{S} Rd,Rm // 乘法运算。Rd = Rd * Rm,{S}NZ。
0100 0011 10mm mddd -- BIC{S} Rd,Rm // 位清除运算。Rd = Rd &(~Rm),{S}NZ。
0100 0011 11mm mddd -- MVN{S} Rd,Rm // 数据非传送。 Rd = ~Rm,{S}NZ。
0100 0100 hhmm mddd -- ADD{S} Rd,Rm // 加法运算。Rd = Rd + Rm,hh若Rd 、Rm为R0--R7时影响{S}NZCV。
0100 0101 hhmm mnnn -- CMP{S} Rn,Rm // 比较刷新{S}。hh若Rd 、Rm为R0--R7时Rn - Rm -->{S}NZCV。
0100 0110 hhmm mddd -- MOV{S} Rd,Rm // 寄存器数据传送。Rd = Rm,hh若Rd 、Rm为R0--R7时影响{S}NZ,清0、CV 。
0100 0111 0Hmm mSBZ -- BX Rm // 带状态切换跳转。PC = Rm。若Rm[0]=1进入Thumb状态,若Rm[0]=0则进入ARM状态。
0100 0111 1Hmm mSBZ -- BLX Rm // 带连接和状态切换的跳转。PC = Rm[31:1],LR=下一条指令。
0100 1ddd vvvv vvvv -- LDR Rd,[PC,#immed_8*4] // 基于PC加载字数据。Rd = [PC + immed_8*4]。
0101 000m mmnn nddd -- STR Rd,[Rn,Rm] // 存储字数据。 [Rn + Rm] = Rd。Rn基址寄存器,Rm偏移量寄存器。
0101 001m mmnn nddd -- STRH Rd,[Rn,Rm] // 存储半字数据。 [Rn + Rm] = Rd。Rn基址寄存器,Rm偏移量寄存器。
0101 010m mmnn nddd -- STRB Rd,[Rn,Rm] // 存储字节数据。 [Rn + Rm] = Rd。Rn基址寄存器,Rm偏移量寄存器。
0101 011m mmnn nddd -- LDRSB Rd,[Rn,Rm] // 加载有符号字节数据。 Rd = [Rn + Rm]。自动扩展为32位有符号数据才放入Rd。
0101 100m mmnn nddd -- LDR Rd,[Rn,Rm] // 加载字数据。 Rd = [Rn + Rm]。Rn基址寄存器,Rm偏移量寄存器。
0101 101m mmnn nddd -- LDRH Rd,[Rn,Rm] // 加载无符号半字数据。 Rd = [Rn + Rm]。Rn基址寄存器,Rm偏移量寄存器。
0101 110m mmnn nddd -- LDRB Rd,[Rn,Rm] // 加载无符号字节数据。 Rd = [Rn + Rm]。Rn基址寄存器,Rm偏移量寄存器。
0101 111m mmnn nddd -- LDRSH Rd,[Rn,Rm] // 加载有符号半字数据。 Rd = [Rn + Rm]。自动扩展为32位有符号数据才放入Rd。
0110 0vvv vvnn nddd -- STR Rd,[Rn,#immed_5*4] // 存储字数据。 [Rn +immed_5*4] = Rd。Rn基址寄存器,immed_5*4为偏移offset。
0110 1vvv vvnn nddd -- LDR Rd,[Rn+#immed_5*4] // 加载字数据。 Rd = [Rn +immed_5*4]。Rn基址寄存器,immed_5*4为偏移offset。
0111 1vvv vvnn nmmm -- LDRB Rd,[Rn,#immed_5] // 加载字节数据。 Rd = [Rn +immed_5]。Rn基址寄存器,immed_5为偏移offset。
0111 0vvv vvnn nddd -- STRB Rd,[Rn,#immed_5] // 存储字节数据。 [Rn +immed_5] = Rd。Rn基址寄存器,immed_5为偏移offset。
1000 0vvv vvnn nddd -- STRH Rd,[Rn,#immed_5*2]// 存储半字数据。 [Rn +immed_5*2] = Rd。Rn基址寄存器,immed_5*2为偏移offset。
1000 1vvv vvnn nddd -- LDRH Rd,[Rn,#immed_5*2]// 加载半字数据。 Rd = [Rn +immed_5*2]。Rn基址寄存器,immed_5*2为偏移offset。
1001 0ddd vvvv vvvv -- STR Rd,[SP,#immed_8*4] // 基于SP存储字数据。 [Rn +immed_8*4] = Rd。SP基址寄存器,immed_8*4为偏移offset。
1001 1ddd vvvv vvvv -- LDR Rd,[SP,#immed_8*4] // 基于SP加载字数据。 Rd = [Rn +immed_8*4]。SP基址寄存器,immed_8*4为偏移offset。
1010 0ddd vvvv vvvv -- ADD Rd,PC,#immed_8*4 // 加法运算。Rd = PC + immed_8*4。
1010 1ddd vvvv vvvv -- ADD Rd,SP,#immed_8*4 // 加法运算。Rd = SP + immed_8*4。
1011 0000 0vvv vvvv -- ADD SP,#immed_7*4 // 加法运算。SP = SP + immed_7*4。
1011 0000 1vvv vvvv -- SUB Sp,#immed_7*4 // 减法运算。SP = SP - immed_7*4。
1011 010R rrrr rrrr -- PUSH reg_list // 压栈。 STMDB SP!。reglist:低寄存器R0--R7的全部或其子集,{reglist,LR}。
1011 110R rrrr rrrr -- POP reg_list // 弹出。LDMIA SP!。{reglist,PC}。
1011 1110 vvvv vvvv -- BKPT immed_8 // 软件断点。预取中止或进入调试状态。
1100 0nnn rrrr rrrr -- STMIA Rn!,reg_list // 批量寄存器回存。reg_list-->[Rn]!。Rn起始地址寄存器
1100 1nnn rrrr rrrr -- LDMIA Rn!,reg_list // 批量寄存器加载。reg_list<--[Rn]!。Rn起始地址寄存器
1101 cccc vvvv vvvv -- Bc signed_immed_8 // 条件cccc跳转指令。PC = PC + signed_immed_8
1101 1111 vvvv vvvv -- SWI immed_8 // 软中断。
1110 0vvv vvvv vvvv -- B signed_immed_11 // 无条件跳转指令。PC = PC + signed_immed_11
111h hvvv vvvv vvvv -- BL(X) immed_11 // 带连接(状态切换)的跳转指令。PC = PC + signed_immed_11,LR=下一条指令。