• AVR汇编(五):算术和逻辑指令


    AVR汇编(五):算术和逻辑指令

    算术运算指令#

    AVR中对于算术运算提供了加法、减法和乘法指令,没有除法指令。

    ADD#

    image.png

    ADD 指令用于执行加法操作,相关的变体指令有:一般加法 ADD 、带进位加法 ADC 、16位立即数加法 ADIW

    例如:

    LDI R16, 0x01    ; R16 = 0x01
    LDI R17, 0x02    ; R17 = 0x02
    ADD R16, R17     ; R16 = 0x03
    
    SEC              ; C = 1
    ADC R16, R17     ; R16 = 0x06, C = 0
    
    LDI R25, 0x0F    ; R25 = 0x0F
    LDI R24, 0xF0    ; R24 = 0xF0
    ADIW R24, 0x10   ; R25:R24 = 0x1000
    

    注意:AVR不支持8位数的立即数加法,即没有 ADDI / ADCI 这样的指令!

    SUB#

    image.png

    SUB 指令用于执行减法操作,相关的变体指令有:一般减法 SUB 、立即数减法 SUBI 、带进位的减法 SUBC 、带进位的立即数减法 SBCI 、16位立即数减法 SBIW

    例如:

    LDI R16, 0x81     ; R16 = 0x81
    LDI R17, 0x80     ; R17 = 0x80
    SUB R16, R17      ; R16 = 0x01
    
    SUBI R17, 0x10    ; R17 = 0x70
    
    SEC               ; C = 1
    LDI R16, 0x80     ; R16 = 0x80
    SBC R16, R17      ; R16 = 0x0F, C = 0
    
    SEC               ; C = 1
    SBCI R16, 0x02    ; R16 = 0x0C, C = 0
    
    LDI R25, 0x02     ; R25 = 0x02
    LDI R24, 0x03     ; R24 = 0x03
    SBIW R24, 0x04    ; R25:R24 = 0x01FF
    

    INC / DEC#

    image.png

    INC 指令用于执行加一操作, DEC 指令用于执行减一操作。需要注意的是,这两条指令都不会影响标志位 C

    例如:

    LDI R16, 0x7F    ; R16 = 0x7F
    INC R16          ; R16 = 0x80
    DEC R16          ; R16 = 0x7F
    

    MUL#

    image.png

    MUL 指令用于执行乘法操作,计算结果存放在 R0R1 寄存器中。默认执行的是无符号数乘法,后缀带 S 表示执行的是符号数乘法,后缀带 SU 表示执行的是符号数与无符号数乘法,前缀带 F 表示执行分数乘法。

    例如:

    LDI R16, 0xFE      ; R16 = 0xFE (-2/254)
    LDI R17, 0x03      ; R17 = 0x03 (3)
    MUL R16, R17       ; R1:R0 = 0x02FA (762)
    MULS R16, R17      ; R1:R0 = 0xFFFA (-6)
    MULSU R16, R17     ; R1:R0 = 0xFFFA (-6)
    FMUL R16, R17      ; R1:R0 = 0x05F4 (1524)
    FMULS R16, R17     ; R1:R0 = 0xFFF4 (-12)
    FMULSU R16, R17    ; R1:R0 = 0xFFF4 (-12)
    

    逻辑运算指令#

    AND / OR / EOR#

    image.png

    AND 用于执行“与”操作, OR 用于执行“或”操作, EOR 用于执行“异或”操作,后缀带 I 表示操作数是立即数。

    例如:

    LDI R16, 0xAA     ; R16 = 0xAA
    LDI R17, 0x0F     ; R17 = 0x0F
    AND R16, R17      ; R16 = 0x0A
    
    ANDI R16, 0x03    ; R16 = 0x02
    
    OR R16, R17       ; R16 = 0x0F
    ORI R16, 0xAA     ; R16 = 0xAF
    
    EOR R16, R17      ; R16 = 0xA0
    

    注意:AVR中“异或”操作不支持立即数,即没有 EORI 这样的指令!

    COM / NEG#

    image.png

    COM 指令用于计算反码(对原码取反), NEG 指令用于计算补码(对原码取反加一)。

    例如:

    LDI R16, 0xA5    ; R16 = 0xA5
    COM R16          ; R16 = 0x5A
    NEG R16          ; R16 = 0xA6
    

    SBR / CBR#

    image.png

    SER 指令用于根据掩码 K 设置寄存器中的某些位,与 ORI 指令作用相同。 CBR 指令用于根据掩码 K 清除寄存器中的某些位,即执行“与非”操作。

    LDI R16, 0x0F    ; R16 = 0x0F
    SBR R16, 0x55    ; R16 = 0x5F
    CBR R16, 0x55    ; R16 = 0x0A
    

    TST / CLR / SER#

    image.png

    TST 指令用于测试寄存器的值是否是零或者负数, CLR 指令将寄存器值设为0, SER 指令将寄存器值设为0xFF。

    例如:

    LDI R16, 0xAA    ; R16 = 0xAA
    TST R16          ; S = 1, V = 0, N = 1, Z = 0
    CLR R16          ; R16 = 0, S = 0, V = 0, N = 0, Z = 1
    SER R16          ; R16 = 0xFF
    

    状态标志位#

    和上一篇介绍的数据传送指令不同,算术和逻辑指令会改变 SREG 寄存器中的标志位,下面介绍其中最常用的4个: ZNVC

    Z 标志位#

    Z 标志位指示计算结果是否为0,当结果为0时置位。

    例如:

    LDI R16, 5     ;             Z = ?
    SUBI R16, 2    ; result = 3, Z = 0
    SUBI R16, 3    ; result = 2, Z = 1
    

    N 标志位#

    N 标志位指示计算结果是否为负数,当结果小于0时置位。

    例如:

    LDI R16, 1      ;              N = ?, Z = ?
    LDI R17, 2      ;              N = ?, Z = ?
    ADD R16, R17    ; result = 3,  N = 0, Z = 0
    SUBI R16, 3     ; result = 0,  N = 0, Z = 1
    SUBI R16, 1     ; result = -1, N = 1, Z = 0
    

    C / V 标志位#

    C 标志位指示计算结果是否超过无符号数范围,当结果超过[0, 255]时置位。

    V 标志位指示计算结果是否超过符号数范围,当结果超过[-128, 127]时置位。

    比如,对于0x7F+0x01=0x80,从无符号数角度看,就是127+1=128,没有超过无符号数范围,故 C 为0。从符号数角度看,127+1=128(-128),超过了符号数范围,故 V 为1。

    再比如,对于0xFE+0x02=0x00,从无符号数角度看,为254+2=256(0),超过了无符号数范围,故 C 为1。从符号数角度看,-2+2=0,没有超过符号数范围,故 V 为0。

    更多例子:

    LDI R17, 4      ;                           N = ?, Z = ?, V = ?, C = ?
    LDI R18, 2      ;                           N = ?, Z = ?, V = ?, C = ?
    LDI R19, 1      ;                           N = ?, Z = ?, V = ?, C = ?
    LDI R16, 250    ;                           N = ?, Z = ?, V = ?, C = ?
    ADD R16, R17    ; result = 0xFE/-2/254,     N = 1, Z = 0, V = 0, C = 0
    ADD R16, R18    ; result = 0x00/0/256(0),   N = 0, Z = 1, V = 0, C = 1
    ADD R16, R19    ; result = 0x01/1/1,        N = 0, Z = 0, V = 0, C = 0
    SUBI R16, 2     ; result = 0xFF/-1/-1(255), N = 1, Z = 0, V = 0, C = 1
    

    参考资料#

    1. ATmega328P Datasheet
    2. AVR Instruction Set Manual
    3. Programming and Interfacing ATMEL's AVRs
  • 相关阅读:
    Bean 作⽤域和⽣命周期
    .NET WebAPI 采用 IDistributedCache 实现分布式缓存过滤器 Redis 模式
    QT编程:QT int和float转QString
    一条SQL查询出MySQL数据库中所有表的数据量大小
    html 铆钉跳转指定元素 元素id
    九、kotlin的泛型
    基于JavaSwing开发书店管理系统+论文 毕业设计 课程设计 大作业
    当下的力量(解读版)
    【css】H8_定位
    python学习笔记之word文档提取
  • 原文地址:https://www.cnblogs.com/chinjinyu/p/17626856.html