跳转到主要内容

Cortex-M0中断控制和系统控制(六)

Arm处理器是基于精简指令集计算机(RISC)原理设计的,指令集和相关译码机制较为简单,具有32位Arm指令集和16位Thumb指令集,Arm指令集效率高,但是代码密度低,而Thumb指令集具有更好的代码密度,却仍然保持Arm的大多数性能上的优势,它是Arm指令集的子集。所有Arm指令都是可以有条件执行的,而Thumb指令仅有一条指令具备条件执行功能。Arm程序和Thumb程序可相互调用,相互之间的状态切换开销几乎为零。

Cortex-M0处理器基于ARMv6-M架构,是一款功耗和性能较为均衡的处理器。Cortex-M0只支持56条指令的小指令集,其中大部分指令是16位指令。

Arm Cortex-M 指令集对比:

<center><img src="http://mcu.eetrend.com/files/2021-08/wen_zhang_/100552951-217240-1.png&…; alt=“” width="600"></center>

<strong><font color="#004a85">01、指令集</font> </strong>

<strong>1.1 在处理器内移动数据</strong>

<pre style="overflow-x:auto; background-color:#e9e9e9;">MOV  &lt;Rd&gt;, &lt;Rm&gt; ;Rm and Rn can be high or low registers.<br />
MOVS &lt;Rd&gt;, &lt;Rm&gt;<br />
MOVS &lt;Rd&gt;, #immed8 ;8位立即数值</pre>

<pre style="overflow-x:auto; background-color:#e9e9e9;">MRS  &lt;Rd&gt;, &lt;SpecialReg&gt;<br />
MSR  &lt;SpecialReg&gt;, &lt;Rd&gt;</pre>

<strong>1.2 存储器访问</strong>

确保访问的内存地址是对齐的,这一点很重要。在ARMv6-M架构(包括Cortex-M0和Cortex-M0处理器)上不支持非对齐传输。任何未对齐内存访问的尝试都会导致HardFault异常。

<pre style="overflow-x:auto; background-color:#e9e9e9;">LDR  &lt;Rt&gt;,[&lt;Rn&gt;, &lt;Rm&gt;]    ; Rt = memory[Rn + Rm]<br />
STR  &lt;Rt&gt;,[&lt;Rn&gt;, &lt;Rm&gt;]    ; memory[Rn + Rm] = Rt<br />
LDRH &lt;Rt&gt;,[&lt;Rn&gt;, &lt;Rm&gt;]    ; Rt = memory[Rn + Rm]<br />
STRH &lt;Rt&gt;,[&lt;Rn&gt;, &lt;Rm&gt;]    ; memory[Rn + Rm] = Rt<br />
LDRB &lt;Rt&gt;,[&lt;Rn&gt;, &lt;Rm&gt;]    ; Rt = memory[Rn + Rm]<br />
STRB &lt;Rt&gt;,[&lt;Rn&gt;, &lt;Rm&gt;]    ; memory[Rn + Rm] = Rt</pre>

<pre style="overflow-x:auto; background-color:#e9e9e9;">LDRSH &lt;Rt&gt;,[&lt;Rn&gt;, &lt;Rm&gt;]   ; Rt = SignExtend(memory[Rn + Rm])<br />
LDRSB &lt;Rt&gt;,[&lt;Rn&gt;, &lt;Rm&gt;]   ; Rt = SignExtend(memory[Rn + Rm])</pre>

<pre style="overflow-x:auto; background-color:#e9e9e9;">LDR  &lt;Rt&gt;,[&lt;Rn&gt;, #immed5] ; Rt = memory[Rn + ZeroExtend (#immed5&lt;&lt;2)]<br />
STR  &lt;Rt&gt;,[&lt;Rn&gt;, #immed5] ; memory[Rn + ZeroExtend(#immed5&lt;&lt;2)] = Rt<br />
LDRH &lt;Rt&gt;,[&lt;Rn&gt;, #immed5] ; Rt = memory[Rn + ZeroExtend (#immed5&lt;&lt;1)]<br />
STRH &lt;Rt&gt;,[&lt;Rn&gt;, #immed5] ; memory[Rn + ZeroExtend(#immed5&lt;&lt;1)] = Rt<br />
LDRB &lt;Rt&gt;,[&lt;Rn&gt;, #immed5] ; Rt = memory[Rn + ZeroExtend (#immed5)]<br />
STRB &lt;Rt&gt;,[&lt;Rn&gt;, #immed5] ; memory[Rn + ZeroExtend(#immed5)] = Rt</pre>

<pre style="overflow-x:auto; background-color:#e9e9e9;">LDR  &lt;Rt&gt;,[SP, #immed8]   ; Rt = memory[SP + ZeroExtend(#immed8&lt;&lt;2)]<br />
STR  &lt;Rt&gt;,[SP, #immed8]   ; memory[SP + ZeroExtend(#immed8&lt;&lt;2)] = Rt</pre>

<pre style="overflow-x:auto; background-color:#e9e9e9;">LDR  &lt;Rt&gt;,[PC, #immed8]   ; Rt =memory[WordAligned(PC+4)+ZeroExtend(#immed8&lt;&lt;2)]<br />
LDR  &lt;Rd&gt;, =immed32       ; pseudo instruction translated to LDR &lt;Rt&gt;,[PC, #immed8]<br />
LDR  &lt;Rd&gt;, label          ; pseudo instruction translated to LDR &lt;Rt&gt;,[PC, #immed8]</pre>

<pre style="overflow-x:auto; background-color:#e9e9e9;">LDM &lt;Rn&gt;,{&lt;Ra&gt;, &lt;Rb&gt;,..} ; Load Multiple<br />
// Ra = memory[Rn]<br />
// Rb = memory[Rn + 4],<br />
// ...
</pre>

<pre style="overflow-x:auto; background-color:#e9e9e9;">LDMIA &lt;Rn&gt;!, {&lt;Ra&gt;, &lt;Rb&gt;,..} ; Load Multiple Increment After<br />
LDMFD &lt;Rn&gt;!, {&lt;Ra&gt;, &lt;Rb&gt;,..}<br />
// Ra = memory[Rn],<br />
// Rb = memory[Rn + 4],<br />
// ...<br />
// and then update Rn to last read address plus 4.</pre>

<pre style="overflow-x:auto; background-color:#e9e9e9;">STMIA &lt;Rn&gt;!, {&lt;Ra&gt;, &lt;Rb&gt;,..} ; Store Multiple Increment After<br />
STMEA &lt;Rn&gt;!, {&lt;Ra&gt;, &lt;Rb&gt;,..}<br />
// memory[Rn] = Ra,<br />
// memory[Rn + 4] = Rb,<br />
// ...<br />
// and then update Rn to last store address plus 4.</pre>

<strong>1.3 栈空间访问</strong>

<pre style="overflow-x:auto; background-color:#e9e9e9;">PUSH {&lt;Ra&gt;, &lt;Rb&gt;, ..}<br />
PUSH {&lt;Ra&gt;, &lt;Rb&gt;, .., LR}<br />
POP  {&lt;Ra&gt;, &lt;Rb&gt;, ..}<br />
POP  {&lt;Ra&gt;, &lt;Rb&gt;, .., PC}</pre>

<strong>1.4 算数运算</strong>

<pre style="overflow-x:auto; background-color:#e9e9e9;">ADD  &lt;Rd&gt;, &lt;Rm&gt;          ; Rd = Rd + Rm. Rd, Rm can be high or low registers.</pre>

<pre style="overflow-x:auto; background-color:#e9e9e9;">ADDS &lt;Rd&gt;, &lt;Rn&gt;, &lt;Rm&gt;    ; Rd = Rn + Rm<br />
SUBS &lt;Rd&gt;, &lt;Rn&gt;, &lt;Rm&gt;    ; Rd = Rn – Rm<br />
ADDS &lt;Rd&gt;, &lt;Rn&gt;, #immed3 ; Rd = Rn + ZeroExtend(#immed3)<br />
SUBS &lt;Rd&gt;, &lt;Rn&gt;, #immed3 ; Rd = Rn – ZeroExtend(#immed3)<br />
ADDS &lt;Rd&gt;, #immed8       ; Rd = Rd + ZeroExtend(#immed8)<br />
SUBS &lt;Rd&gt;, #immed8       ; Rd = Rd – ZeroExtend(#immed8)</pre>

<pre style="overflow-x:auto; background-color:#e9e9e9;">ADCS &lt;Rd&gt;, &lt;Rd&gt;, &lt;Rm&gt;    ; Rd = Rd + Rm + Carry<br />
SBCS &lt;Rd&gt;, &lt;Rd&gt;, &lt;Rm&gt;    ; Rd = Rd – Rm – Borrow</pre>

<pre style="overflow-x:auto; background-color:#e9e9e9;">ADD  SP, SP, #immed7     ; SP = SP + ZeroExtend(#immed7&lt;&lt;2)<br />
SUB  SP, SP, #immed7     ; SP = SP – ZeroExtend(#immed7&lt;&lt;2)<br />
ADD  SP, &lt;Rm&gt;            ; SP = SP + Rm. Rm can be high or low register.</pre>

<pre style="overflow-x:auto; background-color:#e9e9e9;">ADD  &lt;Rd&gt;, SP, &lt;Rd&gt;      ; Rd = Rd + SP. Rd can be high or low register.<br />
ADD  &lt;Rd&gt;, SP, #immed8   ; Rd = SP + ZeroExtend(#immed8&lt;&lt;2)</pre>

<pre style="overflow-x:auto; background-color:#e9e9e9;">ADD  &lt;Rd&gt;, PC, #immed8   ; Rd = (PC[31:2]&lt;&lt;2) + ZeroExtend(#immed8&lt;&lt;2)<br />
ADR  &lt;Rd&gt;, &lt;label&gt;       ; pseudo instruction translated to ADD &lt;Rd&gt;, PC, #immed8</pre>

<pre style="overflow-x:auto; background-color:#e9e9e9;">RSBS &lt;Rd&gt;, &lt;Rn&gt;,#0       ; Rd = 0 – Rm, Reverse Subtract (negative)</pre>

<pre style="overflow-x:auto; background-color:#e9e9e9;">MULS &lt;Rd&gt;, &lt;Rm&gt;, &lt;Rd&gt;    ; Rd = Rd * Rm</pre>

<pre style="overflow-x:auto; background-color:#e9e9e9;">CMP &lt;Rn&gt;, #immed8        ; Rd – ZeroExtended(#immed8)<br />
CMP &lt;Rn&gt;, &lt;Rm&gt;           ; Rn – Rm<br />
CMN &lt;Rn&gt;, &lt;Rm&gt;           ; Rn – NEG(Rm)</pre>

<strong>1.5 逻辑运算</strong>

<pre style="overflow-x:auto; background-color:#e9e9e9;">ANDS <Rd>, <Rd>, <Rm> ; Rd = AND(Rd, Rm)ANDS &lt;Rd&gt;, &lt;Rd&gt;, &lt;Rm&gt; ; Rd = AND(Rd, Rm)<br />
ORRS &lt;Rd&gt;, &lt;Rd&gt;, &lt;Rm&gt; ; Rd = OR(Rd, Rm)<br />
EORS &lt;Rd&gt;, &lt;Rd&gt;, &lt;Rm&gt; ; Rd = XOR(Rd, Rm)<br />
BICS &lt;Rd&gt;, &lt;Rd&gt;, &lt;Rm&gt; ; Rd = AND(Rd, NOT(Rm))<br />
MVNS &lt;Rd&gt;, &lt;Rm&gt;       ; Rd = NOT(Rm)<br />
TST  &lt;Rn&gt;, &lt;Rm&gt;       ; AND(Rn, Rm)</pre>

<strong>1.6 移位和循环操作</strong>

<pre style="overflow-x:auto; background-color:#e9e9e9;">ASRS &lt;Rd&gt;, &lt;Rm&gt;, #immed5 ; Rd = Rm&gt;&gt;immed5<br />
LSLS &lt;Rd&gt;, &lt;Rm&gt;, #immed5 ; Rd = Rm&lt;&lt;#immed5<br />
LSRS &lt;Rd&gt;, &lt;Rm&gt;, #immed5 ; Rd = Rm&gt;&gt;#immed5<br />
ASRS &lt;Rd&gt;, &lt;Rd&gt;, &lt;Rm&gt;    ; Rd = Rd&gt;&gt;Rm<br />
LSLS &lt;Rd&gt;, &lt;Rd&gt;, &lt;Rm&gt;    ; Rd = Rd&lt;&lt;Rm<br />
LSRS &lt;Rd&gt;, &lt;Rd&gt;, &lt;Rm&gt;    ; Rd = Rd&gt;&gt;Rm<br />
RORS &lt;Rd&gt;, &lt;Rd&gt;, &lt;Rm&gt;    ; Rd = Rd rotate right by Rm bits<br />
// Rotate_Left(Data, offset) = Rotate_Right(Data, (32-offset))</pre>

<strong>1.7 展开和顺序反转操作</strong>

这些反向指令通常用于在小端和之间转换数据大整数。

<pre style="overflow-x:auto; background-color:#e9e9e9;">REV &lt;Rd&gt;, &lt;Rm&gt; ; Byte-Reverse Word<br />
// Rd = {Rm[7:0], Rm[15:8], Rm[23:16], Rm[31:24]}</pre>

<pre style="overflow-x:auto; background-color:#e9e9e9;">REV16 &lt;Rd&gt;, &lt;Rm&gt; ; Byte-Reverse Packed Half Word<br />
// Rd = {Rm[23:16], Rm[31:24], Rm[7:0] , Rm[15:8]}</pre>

<pre style="overflow-x:auto; background-color:#e9e9e9;">REVSH &lt;Rd&gt;, &lt;Rm&gt; ; Byte-Reverse Signed Half Word<br />
// Rd = SignExtend({Rm[7:0] , Rm[15:8]})</pre>

<strong>1.8 扩展操作</strong>

它们通常用于数据类型转换。

<pre style="overflow-x:auto; background-color:#e9e9e9;">SXTB &lt;Rd&gt;, &lt;Rm&gt; ; Signed Extended Byte<br />
// Rd = SignExtend(Rm[7:0])</pre>

<pre style="overflow-x:auto; background-color:#e9e9e9;">SXTH &lt;Rd&gt;, &lt;Rm&gt; ; Signed Extended Half Word<br />
// Rd = SignExtend(Rm[15:0])
</pre>

<pre style="overflow-x:auto; background-color:#e9e9e9;">UXTB &lt;Rd&gt;, &lt;Rm&gt; ; Unsigned Extended Byte<br />
// Rd = ZeroExtend(Rm[7:0])</pre>

<pre style="overflow-x:auto; background-color:#e9e9e9;">UXTH &lt;Rd&gt;, &lt;Rm&gt; ; Unsigned Extended Half Word<br />
// Rd = ZeroExtend(Rm[15:0])</pre>

<strong>1.9 程序流控制</strong>

<pre style="overflow-x:auto; background-color:#e9e9e9;">B &lt;label&gt;       ; Branch, Branch range is ±2046 bytes of current PC<br />
B&lt;cond&gt; &lt;label&gt; ; Conditional Branch, Branch range is ±254 bytes of current PC<br />
BL &lt;label&gt;      ; Branch and Link, Branch range is ±16 MB of current PC<br />
BX &lt;Rm&gt;         ; Branch and Exchange<br />
BLX &lt;Rm&gt;        ; Branch and Link with Exchange</pre>

条件转移指令B

<center><img src="http://mcu.eetrend.com/files/2021-08/wen_zhang_/100552951-217242-2.png&…; alt=“Cortex-M0中断控制和系统控制(六)"></center>

<strong>1.10 内存屏障指令</strong>

在Cortex-M0和Cortex-M0处理器上支持内存屏障指令,从而在Cortex-M处理器和其他ARM处理器家族中提供更好的兼容性。

//数据内存屏障,确保所有内存访问都完成

//在新的内存访问被提交之前。

<pre style="overflow-x:auto; background-color:#e9e9e9;">DMB</pre>

//数据同步屏障,确保所有的内存访问都完成

//在执行下一条指令之前。

<pre style="overflow-x:auto; background-color:#e9e9e9;">DSB</pre>

//指令同步障碍,刷新管道和

//确保之前所有的指令都已完成

//在执行新指令之前。

<pre style="overflow-x:auto; background-color:#e9e9e9;">ISB</pre>

<strong>1.11 异常相关指令</strong>

<pre style="overflow-x:auto; background-color:#e9e9e9;">SVC &lt;immed8&gt; ; Supervisor call<br />
CPSIE I      ; Enable Interrupt (Clearing PRIMASK)<br />
CPSID I      ; Disable Interrupt (Setting PRIMASK)</pre>

<strong>1.12 睡眠模式功能相关说明</strong>

//等待中断,停止程序执行,直到一个中断到达,

//如果处理器进入调试状态。

<pre style="overflow-x:auto; background-color:#e9e9e9;">WFI</pre>

//等待事件,如果设置了内部事件寄存器,则清除

//内部事件注册和继续执行。

//停止程序执行,直到事件(如中断)到达

//如果处理器进入调试状态。

<pre style="overflow-x:auto; background-color:#e9e9e9;">WFE</pre>

//发送事件,设置本地事件寄存器并发送一个事件脉冲

//多处理器系统中的其他微处理器。

<pre style="overflow-x:auto; background-color:#e9e9e9;">SEV</pre>

<strong>1.13 其他说明</strong>

<pre style="overflow-x:auto; background-color:#e9e9e9;">NOP           ; No Operation<br />
BKPT &lt;immed8&gt; ; Break point<br />
YIELD         ; Execute as NOP on the Cortex-M0 processor</pre>

<strong><font color="#004a85">02、指令说明</font> </strong>

<strong>2.1 可访问high registers的指令</strong>

绝大部分指令只能访问low registers,也就是只能访问R0~R7寄存器。可以访问high registers的指令只有两条,这两条指令都不更新APSR,指令没有S后缀。

<pre style="overflow-x:auto; background-color:#e9e9e9;">MOV  &lt;Rd&gt;, &lt;Rm&gt; ; Rm and Rn can be high or low registers.<br />
ADD  &lt;Rd&gt;, &lt;Rm&gt; ; Rd = Rd + Rm. Rd, Rm can be high or low registers.</pre>

其它两条和SP加法有关的可以访问high registers的指令其本质是ADD指令。

<pre style="overflow-x:auto; background-color:#e9e9e9;">ADD  SP, &lt;Rm&gt;        <br />
ADD  &lt;Rd&gt;, SP, &lt;Rd&gt;  
</pre>

<strong>2.2 分配临时变量的指令</strong>

函数内的临时变量分配到堆栈,进入函数给临时变量分配空间时使用SUB指令。

<pre style="overflow-x:auto; background-color:#e9e9e9;">SUB  SP, SP, #immed7     ; SP = SP – ZeroExtend(#immed7&lt;&lt;2)</pre>

退出函数释放临时变量空间时使用ADD指令。

<pre style="overflow-x:auto; background-color:#e9e9e9;">ADD  SP, SP, #immed7     ; SP = SP + ZeroExtend(#immed7&lt;&lt;2)</pre>

上面两条指令的立即数只有7位,最多可以增减SP指针127个字空间,如果超过127个字,使用这条指令:

<pre style="overflow-x:auto; background-color:#e9e9e9;">ADD  SP, &lt;Rm&gt;            ; SP = SP + Rm. Rm can be high or low register.</pre>

只有ADD指令,没有SUB指令,如果需要SUB,那么给Rm赋值负数即可。

<strong>2.3 取临时变量地址的指令</strong>

在堆栈分配了临时变量空间后,总要取得临时变量的地址才能做进一步的操作。

<pre style="overflow-x:auto; background-color:#e9e9e9;">ADD  &lt;Rd&gt;, SP, #immed8   ; Rd = SP + ZeroExtend(#immed8&lt;&lt;2)</pre>

立即数不够,可以用寄存器。

<pre style="overflow-x:auto; background-color:#e9e9e9;">ADD  &lt;Rd&gt;, SP, &lt;Rd&gt;      ; Rd = Rd + SP. Rd can be high or low register.</pre>

<strong>2.4 RSBS指令</strong>

<pre style="overflow-x:auto; background-color:#e9e9e9;">RSBS &lt;Rd&gt;, &lt;Rn&gt;, #0       ; Rd = 0 – Rm, Reverse Subtract (negative)</pre>

这是倒过来的减法,常量减去寄存器值,而且常量只能是0。所以这条指令实质上就是一条取负数指令。

Rd = 0 - Rm

等价于:Rd = -Rm

Rd 寄存器值等于负的 Rm 寄存器值。

来源:<a href="https://mp.weixin.qq.com/s/pfzqhB31gUDdbYPvDOzZaQ">灵动MM32MCU</a&gt;
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。