Loading

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
posted @ 2023-08-13 17:17  chinjinyu  阅读(518)  评论(1编辑  收藏  举报