📄 arm 指令格式和时序.htm
字号:
</PRE>
<P>在 ARM6
和以后的处理器上有六个状态寄存器。一个是当前处理器状态寄存器(CPSR),持有关于当前处理器状态的信息。其它五个是保存的程序状态寄存器(SPSR):
每个特权模式都有一个,持有完成在这个模式下的例外处理时处理器必须返回的关于状态的信息。
<P>分别使用 MSR 和 MRS 指令来设置和读取这些寄存器。
<P>
<HR>
<A name=Pipeline>
<H2>流水线</H2></A>
<P>不同于微编码的处理器,ARM (保持它的 RISC 性)是完全硬布线的。
<P>为了加速 ARM 2 和 3 的执行使用 3
阶段流水线。第一阶段持有从内存中取回的指令。第二阶段开始解码,而第三阶段实际执行它。故此,程序计数器总是超出当前执行的指令两个指令。(在为分支指令计算偏移量时必须计算在内)。
<P>因为有这个流水线,在分支时丢失 2 个指令周期(因为要重新添满流水线)。所以最好利用条件执行指令来避免浪费周期。例如: <PRE> ...
CMP R0,#0
BEQ over
MOV R1,#1
MOV R2,#2
over
...
</PRE>可以写为更有效的: <PRE> ...
CMP R0,#0
MOVNE R1,#1
MOVNE R2,#2
...
</PRE>
<P>
<HR>
<A name=Timings>
<H2>时序</H2></A>
<P>ARM 指令在时序上是 S、N、I 和 C 周期的混合。
<P>S 周期是 ARM 在其中访问一个顺序的内存位置的周期。
<P>N 周期是 ARM 在其中访问一个非顺序的内存位置的周期。
<P>I 周期是 ARM 在其中不尝试访问一个内存位置或传送一个字到/从一个协处理器的周期。
<P>C 周期是 ARM 在其中与一个协处理器之间在数据总线(对于无缓存的 ARM)或协处理器总线(对于有缓存的 ARM)上写传送一个字的周期。
<P>各种类型的周期都必须至少与 ARM 的时钟周期一样长。内存系统可以伸展它们: 对于典型的 DRAM 系统,结果是:
<UL>
<LI>N 周期变成最小长度的两倍(主要因为 DRAM 在内存访问是非顺序时要求更长的访问协议)。
<LI>S 周期通常是最小长度,但偶尔也会被伸展成 N 周期的长度(在你从一个内存“行”的最后一个字移动到下一行的第一个字的时候<A
href="http://www.linuxforum.net/books/mhss/arm/ARMinstrs.html#Footnote1">[1]</A>)。
<LI>I 周期和 C 周期总是最小长度。 </LI></UL>
<P>对于典型的 SRAM 系统,所有类型的周期典型的都是最小长度。
<P>在 Acorn Archimedes A440/1 使用的 8MHz ARM2 中,一个 S (顺序) 周期是 125ns 而一个 N (非顺序) 周期是
250ns。应当注意到这些时序不是 ARM 的属性,而是内存系统的属性。例如,一个 8MHz ARM2 可以与一个给出 125ns 的 N 周期的 RAM
系统相连接。处理器的速率是 8MHz 只是简单的意味着如果你使任何类型的周期在长度上小于 125ns 则它不保证能够工作。
<P>有缓存的处理器: 所有给出的信息依据 ARM 所见到的时钟周期。它们不按固定的速率发生: 缓存控制逻辑在 cache 不中的时候改变提供给 ARM
的时钟周期来源。
<P>典型的,有缓存的 ARM 有两个时钟输入: “快速时钟” FCLK 和“内存时钟”MCLK。 在 cache 命中的时候,ARM 的时钟使用 FCLK
的速度并且所有类型的周期都是最小的长度: 从这点上看 cache 在效果上是某种 SRAM。在 cache 不中发生的时候,ARM 的时钟同步为
MCLK,接着以 MCLK 速度进行 cache 行添充(依赖于在处理器中涉及的 cache 行的长度使用 N+3S 或 N+7S 个周期),接着 ARM
的时钟被同步回到 FCLK。
<P>在发生内存访问的时候,ARM 将守时操作(be clocked): 但是,可以使用一个叫 NWAIT 的输入来导致涉及到的 ARM
周期不做任何事情,直到正确的字从内存中到来,并在仍有余下的字到来的时候通常不做任何事情(为了避免在 cache 仍忙于重新填充 cache
行的时候得到进一步的内存请求)。有缓存的 ARM 可以被配置成使用 FCLK 和 MCLK 来相互同步(所以 FCLK 是准确的 MCLK 倍数,并且每个
MCLK 时钟周期与一个 FCLK 周期同时开始)或异步的(这种情况下 FCLK 和 MCLK 周期相互之间可以有任何关系)使情况更加复杂。
<P>情况非常复杂。这些行为的近似的描述是,在一个 cache 行不中发生的时候,它所涉及的周期耗用以 MCLK 周期为单位的 cache
行重填充时间(例如,N+3S 或 N+7S),对于 N 周期和 S 周期可能按 DRAM
所描述的那样被伸展,加上一些更多的周期用于重新同步阶段。要得到详情,你需要得到所涉及的处理器的 datasheet。
<P><A name=Footnote1>脚注</A><A name=Footnote1> 1:</A> 内存控制器意图使用这个简单的策略: 如果请求一个 N
周期,则把访问作为不在同一行来对待;如果请求一个 S 周期,除非它效果上是这行的最后一个字(可以被快速检测出来),否则把访问作为同行来对待。结果是一些 S
周期将持续与 N 周期相同的时间;如果我记得正确,在 Archimedes 上 S 周期所访问的内存被按 16 字节来分开。对于 Archimedes
代码的实际后果是: (a) 大约 4 个 S 周期中的 1 个变成一个 N 周期,为此,所有地址都是字地址并按 4 来分开;(b)
有时值得仔细关照对齐代码来避免这种效果并得到一些额外的性能。)
<P>
<HR>
<A name=Instructions>
<H2>指令</H2></A>
<P>每个 ARM 指令都是 32 位宽,下面给出详细的解释。对于每个指令类,我们给出指令位图(bitmap),和典型汇编器使用的语法的例子。
<P>一定要注意助记符的语法不是固定的;它是汇编器的特性,而不是 ARM 机器编码的。
<P><A name=Condition>
<H3>条件代码</H3></A>
<P>每个指令的顶端部分是一个条件代码,所以可以有条件的运行每个单一的 ARM 指令。
<P> <PRE> 条件
指令位图 编号 条件代码 所须标志:
0000xxxx xxxxxxxx xxxxxxxx xxxxxxxx 0 EQ(等于,Equal) Z
0001xxxx xxxxxxxx xxxxxxxx xxxxxxxx 1 NE(不等于,Not Equal) ~Z
0010xxxx xxxxxxxx xxxxxxxx xxxxxxxx 2 CS(进位设置,Carry Set) C
0011xxxx xxxxxxxx xxxxxxxx xxxxxxxx 3 CC(进位清除,Carry Clear) ~C
0100xxxx xxxxxxxx xxxxxxxx xxxxxxxx 4 MI(负号,MInus) N
0101xxxx xxxxxxxx xxxxxxxx xxxxxxxx 5 PL(正号,PLus) ~N
0110xxxx xxxxxxxx xxxxxxxx xxxxxxxx 6 VS(溢出设置,oVerflow Set) V
0111xxxx xxxxxxxx xxxxxxxx xxxxxxxx 7 VC(溢出清除,oVerflow Clear) ~V
1000xxxx xxxxxxxx xxxxxxxx xxxxxxxx 8 HI(高于,HIgher) C and ~Z
1001xxxx xxxxxxxx xxxxxxxx xxxxxxxx 9 LS(低于或同于,Lower or Same) ~C and Z
1010xxxx xxxxxxxx xxxxxxxx xxxxxxxx A GE(大于等于,Greater or equal)N = V
1011xxxx xxxxxxxx xxxxxxxx xxxxxxxx B LT(小于,Less Than) N = ~V
1100xxxx xxxxxxxx xxxxxxxx xxxxxxxx C GT(大于,Greater Than) (N = V) and ~Z
1101xxxx xxxxxxxx xxxxxxxx xxxxxxxx D LE(小于等于,Less or equal) (N = ~V) or Z
1110xxxx xxxxxxxx xxxxxxxx xxxxxxxx E AL(总是,Always) 永真
1111xxxx xxxxxxxx xxxxxxxx xxxxxxxx F NV(从不,Never) 永假
</PRE>
<P>在多数汇编器中,插入条件代码到紧随在助记符根代码(stub)的后面;省略条件代码缺省为使用 AL。
<P>在一些汇编器中把 HS (高于或同于) 和 LO (低于) 分别用做 CS 和 CC 的同义词。
<P>条件 GT、GE、LT、LE 被成为有符号比较,而 HS、HI、LS、LO 被称为无符号比较。
<P>把一个条件代码与 1 进行异或得到相反的条件的代码。
<P>NB: ARM 废弃使用 NV 条件代码 - 假定你使用 MOV R0,R0 作为一个空指令而不是以前推荐的 MOVNV R0,R0
。将来的处理器可能重新使用 NV 条件来做其他事情。
<P>所须条件为假的指令执行 1S 周期,使一个指令有条件执行不招致时间处罚。
<P><A name=Data>
<H3>数据处理指令</H3></A><PRE>xxxx000a aaaSnnnn ddddcccc ctttmmmm 寄存器形式
xxxx001a aaaSnnnn ddddrrrr bbbbbbbb 立即数形式
</PRE>
<P>典型的汇编语法: <PRE> MOV Rd, #0
ADDEQS Rd, Rn, Rm, ASL Rc
ANDEQ Rd, Rn, Rm
TEQP Pn, #&80000000
CMP Rn, Rm
</PRE>
<P>在操作 a 下,组合 Rn 的内容和 Op2,放置结果到 Rd 中。
<P>如果使用寄存器形式,则 Op2 被设置为依据下面描述的 t 来移位的 Rm 的内容。如果使用立即数形式,则 Op2 = #b, ROR #2r。 <! center BOXED ; c l s lc l l l. ><PRE> t 汇编器 解释
000 LSL #c 逻辑左移
001 LSL Rc 逻辑左移
010 LSR #c for c != 0 逻辑右移
LSR #32 for c = 0
011 LSR Rc 逻辑右移
100 ASR #c for c != 0 算术右移
ASR #32 for c = 0
101 ASR Rc 算术右移
110 ROR #c for c != 0 循环右移
RRX for c = 0 带扩展的循环右移一位
111 ROR Rc 循环右移
</PRE>
<P>在寄存器形式中,用位 8-11 表示 Rc;如果使用 Rc 则位 7 必须清除。(如果你编码为 1,你将得到一个乘法、SWP
或未分配的指令而不是一个数据处理指令。)
<P>还有,只使用了 Rc 的底端字节 - 如果 Rc = 256, 则移位将是零。
<P>“MOV[S] Ra,Rb,RLX” 可以通过 ADC[S] Ra,Rb,Rb 来完成,这里的 RLX 意思是带扩展的循环左移一位。
<P>多数汇编器允许使用 ASL 作为 LSL 的同义词。因为对算术左移是什么有不同的意见,最好使用术语 LSL。
<P>通过在 MOV、MVN 或逻辑指令中设置 S 位,(在寄存器或立即数形式中)把进位标志设置为最后移出的那一位。
<P>如果不做移位,则不影响进位标志。
<P>如果立即数有可选择的多个形式(例如,#1 可以表示为 1 ROR #0、4 ROR #2、16 ROR #4 或 64 ROR
#6),则汇编器希望使用涉及零移位的那个形式,如果可获得的话。所以,如果 0 <= const <= 255,则 MOVS Rn,#const
将保持进位标志不受影响,否则将改变它。
<P><! center BOXED ;c l l l. ><PRE>aaaa 汇编器 意思 P-Code
0000 AND 逻辑与 Rd = Rn AND Op2
0001 EOR 逻辑异或 Rd = Rn EOR Op2
0010 SUB 减法 Rd = Rn - Op2
0011 RSB 反向减法 Rd = Op2 - Rn
0100 ADD 加法 Rd = Rn + Op2
0101 ADC 带进位的加法 Rd = Rn + Op2 + C
0110 SBC 带借位的减法 Rd = Rn - Op2 - (1-C)
0111 RSC 带借位的反向减法 Rd = Op2 - Rn - (1-C)
1000 TST 测试位 Rn AND Op2
1001 TEQ 测试等同 Rn EOR Op2
1010 CMP 比较 Rn - Op2
1011 CMN 比较取负 Rn + Op2
1100 ORR 逻辑或 Rd = Rn OR Op2
1101 MOV 传送值 Rd = Op2
1110 BIC 位清除 Rd = Rn AND NOT Op2
1111 MVN 传送取非 Rd = NOT Op2
</PRE>注意 MVN 和 CMN 不是象表面上的那种关系;MVN 使用直接的逐位(bitwise)非操作,把 Rn 设置为 Op2 对 1
的补码(反码)。CMN 把 Rn 与 Op2 对 2 的补码进行比较。
<P>这些指令可归入 4 个子集:
<DL>
<DT>MOV, MVN
<DD>Rn 被忽略,并且应当是 0000。如果设置了 S 位,则在结果上设置 N 和 Z 标志。并且如果使用了移位器,则 C
标志被设置为被移出的最后一位。不影响 V 标志。
<DT>
<DT>CMN, CMP, TEQ, TST
<DD>Rd 不被指令所设置,并且应当是 0000。必须设置 S 位(多数汇编器会自动完成;如果没有设置它,则这个指令将是
MRS、MSR、或一个未分配的指令。)
<P>算术操作(CMN, CMP)在结果上设置 N 和 Z 标志,从 ALU 得到 C 和 V 标志。
<P>逻辑操作(TEQ, TST)在结果上设置 N 和 Z 标志,如果使用了移位器则从它得到 C 标志(在这种情况下它变成被移出的最后一位),不影响 V
标志。
<P>有一个特殊情况(对于 ARMs >= 6,只针对 26 位模式),dddd 字段是 1111
导致用结果的相应的位设置标志(在用户模式下),或整个 26 位 PSR (在特权模式下)。这由给指令的 P 后缀来指示 - CMNP、
CMPP、TEQP、TSTP。常用 TEQP PC,#(新模式编号) 来改变模式。在 32 位模式,应当使用 MSR 来替代(因为 TEQP
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -