⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 arm 指令格式和时序.htm

📁 ARM指令集
💻 HTM
📖 第 1 页 / 共 4 页
字号:
  等不再工作)。</P>
  <DT>ADC, ADD, RSB, RSC, SBC, SUB 
  <DD>如果设置了 S 位,则在结果上设置 N 和 Z 标志,从 ALU 的得到 C 和 V 标志。 
  <DT>  
  <DT>AND, BIC, EOR, ORR 
  <DD>如果设置了 S 位,则在结果上设置 N 和 Z 标志,如果使用了移位器则从它得到 C 标志(在这种情况下它变成被移出的最后一位),不影响 V 标志。 
  </DD></DL>
<P>可以使用 ADD 和 SUB 以与位置无关的方式使寄存器指向数据,例如 ADD R0,PC,#24。这很有用,一些汇编器有一个叫做 ADR 
的特殊宏指令(directive),它自动生成恰当的 ADD 或 SUB 指令。(ADR R0, fred 典型的把 fred 的地址放置到 R0 中,假定 
fred 在范围内)。 
<P>在 26-bit 模式下,在 R15 是使用的寄存器之一的时候发生一种特殊情况: 
<UL>
  <LI>如果 Rn = R15 则使用的 R15 值屏蔽掉了所有 PSR 位。 
  <LI>如果 Op2 涉及 R15,则使用所有的 32 位。 </LI></UL>
<P>在 32-bit 模式下,使用 R15 的所有的位。 
<P>在 26-bit 模式下,如果 Rd = R15 则: 
<UL>
  <LI>如果未设置 S 位,则只设置 PC 的 24 位。 
  <LI>如果设置了 S 位,则覆写 PC 和 PSR 二者(除非在非用户模式下,否则不改变模式位、I 和 F 位。) </LI></UL>
<P>对于 32-bit 模式, 如果 Rd=15,则覆写 PC 的所有的位,不包括最低的那两个有效位,它们总是零。如果未设置 S 
位,则只进行上面这些;如果设置了 S 位,把当前模式的 SPSR 复制到 CPSR 中。在 32-bit 用户模式下,你不应该执行把 PC 
作为目的寄存器并设置了 S 位的指令,因为用户模式没有 SPSR。(顺便说一句,你这样做不会打断处理器 - 
这样做的结果只是未定义而已,且在不同的处理器上可能不同。) 
<P>执行这些指令使用下列数目的周期: 1S + (1S 如果使用了寄存器控制的移位) + (1S + 1N 如果改变了 PC) 
<P><A name=Branch>
<H3>分支指令</H3></A><PRE>xxxx101L oooooooo oooooooo oooooooo
</PRE>
<P>典型的汇编语法: <PRE>        BEQ  地址
        BLNE 子例程
</PRE>
<P>使用这些指令强制跳转到一个新地址,用相对于执行这个指令时 PC 值的以字为单位的偏移量给出这个新地址。 
<P>因为流水线的缘故,PC 总是超出存储这个指令的地址 2 个指令(8 字节),所以分支的偏移量 = (位 0-23 的有符号扩展): <PRE>	目的地址 = 当前地址 + 8 + (4 * 偏移量)
</PRE>在 26-bit 模式下,清除目的地址的顶端 6 位。 
<P>如果设置了 L 位,则在进行这个分支之前把 PC 的当前内容复制到 R14。所以 R14 持有在这个分支后面的指令的地址,被调用的例程可以用 MOV 
PC,R14 返回。 
<P>在 26-bit 模式下,使用 MOVS PC,R14 来从一个带连接的分支返回,在返回时可以自动恢复 PSR 标志。 在 32-bit 模式下 MOVS 
PC,R14 的行为是不同的,并只适合于从例外返回。 
<P>执行分支和带连接的分支二者都使用 2S+1N 个周期。 
<P> </P><A name=Multiplication>
<H3>乘法</H3></A><PRE>xxxx0000 00ASdddd nnnnssss 1001mmmm
</PRE>
<P>典型汇编语法: <PRE>        MULEQS Rd, Rm, Rs
        MLA    Rd, Rm, Rs, Rn
</PRE>
<P>这些指令做两个操作数的乘法,并且可以选择加上第三个操作数,把结果放置到另一个寄存器中。 
<P>如果设置了 S 位,则在结果是设置 N 和 Z 标志,未定义 C 标志,不影响 V 标志。 
<P>如果设置了 A 位,则操作的效果是 Rd = Rm*Rs + Rn,否则是 Rd = Rm*Rs。 
<P>目的寄存器不应该与操作数寄存器 Rm 相同。R15 不应该用于操作数或目的寄存器。 
<P>执行这些指令在最坏的情况下使用 1S + 16I 个周期,并依赖于实际参数的值可以更小。实际时间依赖于 Rs 的值,依照下表: <! center BOXED ;                                               c s lr1 l l. ><PRE>         Rs 的范围         	周期数

           &amp;0 -	&amp;1      	1S + 1I
           &amp;2 -	&amp;7      	1S + 2I
           &amp;8 -	&amp;1F     	1S + 3I
          &amp;20 -	&amp;7F     	1S + 4I
          &amp;80 -	&amp;1FF    	1S + 5I
         &amp;200 -	&amp;7FF    	1S + 6I
         &amp;800 -	&amp;1FFF   	1S + 7I
        &amp;2000 -	&amp;7FFF   	1S + 8I
        &amp;8000 -	&amp;1FFFF  	1S + 9I
       &amp;20000 -	&amp;7FFFF  	1S + 10I
       &amp;80000 -	&amp;1FFFFF 	1S + 11I
      &amp;200000 -	&amp;7FFFFF 	1S + 12I
      &amp;800000 -	&amp;1FFFFFF	1S + 13I
     &amp;2000000 -	&amp;7FFFFFF	1S + 14I
     &amp;8000000 -	&amp;1FFFFFFF	1S + 15I
    &amp;20000000 -	&amp;FFFFFFFF	1S + 16I
</PRE>
<P>这些乘法时序不适用于 ARM7DM。 ARM7DM 时序由下表给出: <! center BOXED ;                                               c s l l l l lc s l l l l lr1 l l l l l l. ><PRE>                        		MLA/
            Rs 的范围    	MUL	SMULL	SMLAL	UMULL	UMLAL

           &amp;0 -	&amp;FF     	1S+1I	1S+2I	1S+3I	1S+2I	1S+3I
         &amp;100 -	&amp;FFFF    	1S+2I	1S+3I	1S+4I	1S+3I	1S+4I
       &amp;10000 -	&amp;FFFFFF  	1S+3I	1S+4I	1S+5I	1S+4I	1S+5I
     &amp;1000000 -	&amp;FEFFFFFF	1S+4I	1S+5I	1S+6I	1S+5I	1S+6I
    &amp;FF000000 -	&amp;FFFEFFFF	1S+3I	1S+4I	1S+5I	1S+5I	1S+6I
    &amp;FFFF0000 -	&amp;FFFFFEFF	1S+2I	1S+3I	1S+4I	1S+5I	1S+6I
    &amp;FFFFFF00 -	&amp;FFFFFFFF	1S+1I	1S+2I	1S+3I	1S+5I	1S+6I
</PRE><A name=Long>
<H3>长乘法(ARM7DM)</A> </H3><PRE>xxxx0000 1UAShhhh llllssss 1001mmmm
</PRE>
<P>典型的汇编语法: <PRE>        UMULL  Rl,Rh,Rm,Rs
        UMLAL  Rl,Rh,Rm,Rs
        SMULL  Rl,Rh,Rm,Rs
        SMLAL  Rl,Rh,Rm,Rs
</PRE>
<P>这些指令做寄存器 Rm 和 Rs 的值的乘法并获得一个 64-bit 乘积。 
<P>在清除了 U 位的时候乘法是无符号的(UMULL 或 UMLAL),否则是有符号的(SMULL, SMLAL)。在清除了 A 
位的时候,把结果的低有效的那一半存储在 Rl 中并把它的高有效的那一半存储到 Rh 中。在设置了 A 位的时候,转而把结果加到 Rh,Rl 的内容上。 
<P>不应该使用程序计数器 R15。Rh、Rl 和 Rm 应该不同。 
<P>如果设置了 S 位,则在 64-bit 位结果是设置 N 和 Z 标志,未定义 C 和 V 标志。 
<P>它们的时序可以在上面的乘法段落中找到。 
<P> </P><A name=Transfer>
<H3>单一数据传送</H3></A><PRE>xxxx010P UBWLnnnn ddddoooo oooooooo  Immediate form
xxxx011P UBWLnnnn ddddcccc ctt0mmmm  Register form
</PRE>
<P>典型的汇编语法: <PRE>        LDR  Rd, [Rn, Rm, ASL#1]!
        STR  Rd, [Rn],#2
        LDRT Rd, [Rn]
        LDRB Rd, [Rn]
</PRE>
<P>这些指令装载/存储内存的一个字从/到一个寄存器。在指定地址时使用的第一个寄存器在术语上叫做基址寄存器。 
<P>如果设置了 L 位,则进行装载,否则进行存储。 
<P>如果设置了 P 位,则使用预先变址寻址,否则使用过后变址寻址。 
<P>如果设置了 U 位,则给出的偏移量被加到基址寄存器上 - 否则从中减去偏移量。 
<P>如果设置了 B 位,传送内存的一个字节,否则传送一个字。这在汇编器中表示为给根助记符的加上后缀‘B’。 
<P>W 位的解释依赖于使用的地址模式: 
<UL>
  <LI>对于预先变址寻址,设置 W 位强制把用做地址转换的最终地址写回基址寄存器中。(例如,传送的副作用是 Rn := Rn +/- 
  offset。这在汇编器中表示为给指令加上后缀 ‘!’。) 
  <LI>对于过后变址寻址,地址总是写回,设置 W 位指示在进行传送之前强制地址转换。这在汇编器中表示为给指令加上后缀‘T’。 </LI></UL>
<P>地址转换导致芯片告知内存系统这是一个用户模式传送,而不管此时芯片是处于用户模式中还是处于特权模式中。这是有用的,例如在写模拟器的时候: 
假如一个用户模式程序一个内存区域执行了一个&nbsp; STF 指令,而用户模式代码不可以写这个内存区域。如果由一个 FPA 来指令它,它将异常终止。如果由一个 
FPE 来执行它,它也应该异常终止。但是 FPE 
运行在一个特权模式下,所以如果它使用普通存储指令,则它不会异常终止。为了使异常终止正确工作,在一个特权模式调用它时使用 STRT 
替代普通存储指令,使其如同调用自用户模式。 
<P>如果使用这个指令的立即数形式,o 字段给出一个 12-bit 
偏移量。如果使用了寄存器形式,则按对数据处理指令那样解码它,限制是不允许使用寄存器指令移位量。 
<P>如果 R15 被用做 Rd,不修改 PSR。PC 不应该被用在 Op2 中。 
<P>其他限制: 
<UL>
  <LI>在基址寄存器是 PC 的时候不要使用写回或过后变址。 
  <LI>不要使用 PC 作为给 LDRB 或 STRB 的 Rd。 
  <LI>在使用带有寄存器偏移量的过后变址时,不要让 Rn 和 Rm 是同一个寄存器(这样做导致不可能从异常终止中恢复)。 </LI></UL>
<P>装载使用 1S + 1N + 1I + (1S + 1N 如果改变了 PC)个周期,而存储使用 2N 个周期。 
<P> </P><A name=Block>
<H3>块数据传送</H3></A><PRE>xxxx100P USWLnnnn llllllll llllllll
</PRE>
<P>典型的汇编语法: <PRE>        LDMFD   Rn!, {R0-R4, R8, R12}
        STMEQIA Rn,   {R0-R3}
        STMIB   Rn,   {R0-R3}^
</PRE>
<P>使用这些指令来同时装载/存储多个寄存器从/到内存。使用的内存地址从在基址寄存器 Rn 
中持有的值指定的内存地址要么增加要么减少地址,(可以存储基址寄存器自身),并且最终的地址可以被写回到基址寄存器中。这些指令适合于实现栈,在进入/退出一个子例程时存储/恢复寄存器的内容。 

<P>U 位指示对每个寄存器地址将被 +4 (设置)所修改,还是被 -4 (清除)所修改。 
<P>W 位总是指示写回。 
<P>如果设置了 L 位,则指示进行一个装载操作,如果清除了,则指示存储。 
<P>使用 P 位指示在每次装载/存储之前还是之后增加/减少基址寄存器(参见下面表格)。 
<P>如果这个操作要装载/存储 Rl 则设置位 l。 
<P>汇编器典型的用条件代码跟随助记符根,并随后用两个字母代码指示 U 和 W 位的设置。 <! center BOXED ;                                               l l l l. ><PRE>根	意思                             	P	U

DA	在每次存储/装载之后减少 Rn        	0	0
DB	在每次存储/装载之前减少 Rn        	1	0
IA	在每次存储/装载之后增加 Rn        	0	1
IB	在每次存储/装载之前增加 Rn        	1	1
</PRE>
<P>在实现栈的时候有更清楚的同义词: <! center BOXED ;                                               l l. ><PRE>根	意思

EA	空升序栈
ED	空降序栈
FA	满升序栈
FD	满降序栈
</PRE>
<P>在一个空栈中,栈指针指向下一个空位置。在一个满栈中栈指针指向最顶端满位置。升序栈向高位置增长,而降序栈向低位置增长。 
<P>存储的寄存器总是最低编号的寄存器在内存中在最低地址。这可以影响入栈和出栈代码。例如,如果我想把 R1-R4 
压入栈中,接着每次把它们中的两个装载回来,要使它们回到原先的寄存器,对于降序栈我需要做类似下面的事: <PRE>   STMFD R13!,{R1,R2,R3,R4}  ;放置 R1 在内存低端,就是说在栈顶
   LDMFD R13!,{R1,R2}
   LDMFD R13!,{R3,R4}

</PRE>对于升序栈则是: <PRE>   STMFA R13!,{R1,R2,R3,R4}  ; 放置 R4 在内存高端,就是说在栈顶
   LDMFA R13!,{R3,R4}
   LDMFA R13!,{R1,R2}

</PRE>
<P>同义的代码如下: <! center BOXED ;                                               c c c. ><PRE>代码	装载	存储

EA	DB	IA
ED	IB	DA
FA	DA	IB

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -