如何在循环中使用ARM ADCS指令?解决CMP破坏标志位问题
解决ARM汇编中ADCS与CMP标志位冲突的问题
核心问题分析
你的代码中,ADCS指令依赖进位标志位C完成带进位的BCD加法,但后续CMP指令会直接覆盖所有条件标志位(包括C),导致下一次ADCS无法正确获取上一次的进位状态。
可行解决方案
方案1:使用MRS/MSR指令保存并恢复标志位
ARM架构中,可通过MRS(从状态寄存器读取到通用寄存器)和MSR(从通用寄存器写入状态寄存器的标志位域),在执行CMP前后保留ADCS设置的进位标志。
修改后的代码如下:
ldr r8, =#0 ldr r9, =#15 adds r7, r8, #0 ADDLOOP: and r4, r0, r9 and r5, r1, r9 adcs r6, r4, r5 ; 执行带进位加法,设置C标志 orr r7, r6, r7 mrs r10, cpsr ; 保存当前标志位状态到r10 add r8, r8, #1 mov r9, r9, lsl #4 cmp r8, #3 ; 此处覆盖标志位,但已提前保存 bgt ADDEND msr cpsr_f, r10 ; 恢复之前保存的标志位(重点保留C标志) b ADDLOOP ; 用b代替bl,避免lr寄存器被覆盖导致错误 ADDEND: mov r0, r7
方案2:重构循环逻辑,避免使用CMP
如果不想保存标志位,可调整循环计数方式,用不破坏进位标志的逻辑判断循环终止。比如改用递减计数,结合SUBS和条件跳转,但需注意SUBS仍会修改标志位,仅适用于进位无需跨循环保留的场景:
ldr r8, =#4 ; 设置循环执行4次 ldr r9, =#15 adds r7, r8, #0 ADDLOOP: and r4, r0, r9 and r5, r1, r9 adcs r6, r4, r5 orr r7, r6, r7 subs r8, r8, #1 ; 递减计数并设置标志位 mov r9, r9, lsl #4 bne ADDLOOP ; 计数未到0则继续循环 ADDEND: mov r0, r7
额外注意点
- 原代码中
bl ADDLOOP是错误用法:bl会将当前指令下一条地址存入lr寄存器,多次循环会覆盖lr,导致程序后续无法正确返回,需改为b ADDLOOP实现循环跳转。 - 保存标志位时,需选用闲置的通用寄存器(如示例中的
r10),避免干扰其他逻辑。
内容的提问来源于stack exchange,提问作者xxxx
相关产品推荐
相关产品推荐

