使用AVR汇编程序将两个16位数字相乘

时间:2019-05-23 05:42:03

标签: avr atmega

我编写了一个代码,用于计算一个三角形区域,该区域在两个寄存器(R16和R18)中加载了基数和高值。这些是8位值

 .include "./m2560def.inc"  
;------------------------------------------------------------------
; Constants
;------------------------------------------------------------------
.def    base    = r16
.def    high    = r17

.equ    base_value  = 10
.equ    high_value = 20

    .cseg
        .org    0x0000
        rjmp    reset           ; reset intr
reset:
        LDI R16, HIGH(RAMEND)
        OUT SPH, R16
        LDI R16, LOW(RAMEND)
        OUT SPL, R16

RCALL   configure_ports

start:
        LDI base, base_value
        LDI high, high_value 
        MUL base, high
        MOVW R18, R0
        LSR  R18         ;divide by 2 
        MOV  R19, R18
        OUT  PORTB, R19  ;Output result in PORTB
        OUT  PORTD, R19  ;Output result in PORTD
        RJMP    start

configure_ports:
        ;Configurare B and C ports as outputs
        LDI R16, 0XFF
        OUT DDRB, R16
        OUT DDRC, R16
        ret

如果我使用16位数字作为基数和高位,如何将其加载到两个寄存器中并计算16位的(基数x高)和(基数x高)/ 2操作?

1 个答案:

答案 0 :(得分:0)

如果您了解如何在纸上执行十进制乘法,那么将很容易用8位数字替换十进制数字。

假设您有两个十进制数字:AB和XY(其中A,B,X,Y是十进制数字)。 您可以将其表示为两位数乘以一位数的和:

AB * XY =(AB * Y)+((AB * X)<< 1d)(其中<< 1d表示左移一位数字,等于十进制的10乘)

两位数与一位数的乘积可以用与

相同的术语表示

AB * Y =(B * Y)+((A * Y)<< 1d)

或整个扩展可以写为:

AB * XY =(B * Y)+((A * Y)<< 1d)+((B * X)<< 1d)+((A * X)<< 2d)

现在,假设以上示例中的每个数字都是一个字节,您就可以从十进制转换为基于256的系统。

因此,要查找AB * XY的乘法,您需要:

  1. 计算B * Y,并将其存储到4字节结果中(两个高字节为零)
  2. 计算B * X,将其向左移1个字节,加到结果中
  3. 计算A * Y,将其左移1个字节,然后添加到结果中
  4. 计算A * X,将其左移2个字节,然后添加到结果中

在assmbler中,它可能如下所示: 假设我们有:

  • r25:r24 -第一个乘数
  • r23:r22 -第二个
  • r21:r20:r19:r18 -结果

代码如下:

clr r16 // a zero register, we'll need it in the future

mul r24, r22 // r1:r0 = r24 * r22
movw r0, r18 // move result to r19:r18
clr r20 // clear r21 and r22
clr r21

mul r24, r23 // r1:r0 = r24 * r23
add r19, r0 // add to the result starting from the second from the right byte (r19)
adc r20, r1 // add next byte with carry
adc r21, r16 // add zero with carry

mul r25, r22 // r1:r0 = r25 * r22
add r19, r0 // add to the result starting from the second from the right byte (r19)
adc r20, r1 // add next byte with carry
adc r21, r16 // add zero with carry

mul r25, r23 // r1:r0 = r25 * r23
add r20, r0 // add to the result starting from the third from the right byte (r20)
adc r21, r1 // add next byte with carry

干得好!现在,您在r21:r20:r19:r18有了四字节的结果

要除以2,您只需将结果1二进制位置向右移动即可。您需要两个说明:

  • lsr -逻辑右移。它将位向右移动一个位置。最左边的位置填充零,而推出的最右边的位置存储在进位标志中。
  • ror -通过进位向右旋转。它的作用相同:将位向右移一个位置,并将推出的最右边位置存储在进位中,但最左边的位置由进位标志的初始值填充

代码:

lsr r21
ror r20
ror r19
ror r18

现在将四字节值除以2(向下舍入)