ATmega128:添加和减去16位数字(汇编)

时间:2012-02-09 20:58:02

标签: assembly microcontroller atmel

我正在使用ATmega128微控制器,据说需要添加两个16位数字。我正在使用AVR Studio,这是我到目前为止所得到的:

.include "m128def.inc";

.equ    ramstart = 0x100
.def    temp = r16

.dseg
.org ramstart
number1: .byte 2
number2: .byte 2

.cseg
.org 0

rjmp start

start:
    ; number1 := 0x7856
    ldi temp, low(number1)
    sts number1, temp
    ldi temp, high(number1)
    sts number1+1, temp

    ; number2 := 0x34B2
    lds temp, number1
    sts number2, temp
    lds temp, number1+1
    sts number2+1, temp

slutt:
    rjmp slutt

这离我第一次使用任何类型的装配都不远,我知道我做错了什么,但似乎无法弄清楚是什么。我错过了携带标志吗?

4 个答案:

答案 0 :(得分:8)

用铅笔和纸回到成绩学校。如果我想添加1234和5678

  1234
+ 5678
======

4 + 8是2携带1

    1
  1234
+ 5678
======
     2    

等等

 00110 <-- carry bits
  1234 <-- first operand
+ 5678 <-- second operand
======
  6912

一列上方的进位是重要的,它被称为进位和进位 离开最左边一列的位是执行的。

如果我的纸张足够宽,一次只能添加两列,该怎么办?

 110 
  34 
+ 78 
======
  12

我从两个较低的数字位开始,我需要一个零作为进位。我得到一个带有执行的结果12。

现在我把它拿出来,用它作为接下来两位数的进位。这个加法器我必须能够从之前的添加中取出并将其用作此添加的进位。

 001
  12
+ 56
====
  69

当说完所有的时候我得到69和12,把它们放在一起我得到6912但是不需要一个完整的4位加法器来达到那里。您可以永久重复此操作,也可以直到内存,寄存器或时钟周期耗尽为止。

avr可能有其他方法可以解决问题,但大多数处理器至少有两种形式的加法和两种形式的减法,这样你就可以将加法器级联到你需要的范围内。检查avr的指令集,上面发生的事情应该跳出来。

编辑:

C示例可能会有所帮助......(切换到十六进制)

unsigned int a,b,c,d,cin,cout,x,y;

a=0x12; b=0x34;
c=0x56; d=0x78;

x=b+d; //dont want a carry in or assume it is zero
cout=x&0x100; 
if(cout) cin=1; else cin=0;
y=a+c+cin; //need the carry out on the prior add as the carry in here

x&=0xFF;
y&=0xFF;

printf("0x%02X%02X\n",y,x);

EDIT2:

我希望这不是家庭作业......

ldi r20,0x12
ldi r21,0x34
ldi r22,0x56
ldi r23,0x78
add r21,r23
adc r20,r22

结果是r20高字节,r21低字节

如果你需要从ram读取有很多方法,这假设16位数字是小端

lds r0,0x100
lds r1,0x101
lds r2,0x102
lds r3,0x103
add r0,r2
adc r1,r3

r0结果的一半,r1的上半部分。

或使用x,y或z指针寄存器之一

;put 0x0100 in Z
ldi r30,0x00
ldi r31,0x01
ld r0,z+
ld r1,z+
ld r2,z+
ld r3,z+
add r0,r2
adc r1,r3

答案 1 :(得分:1)

嗯,你并没有真正发出任何加法指示。我不是一个AVR程序员,但是在快速浏览一下ATmega128的指令集之后,这样的事情似乎更正确了。我假设您的汇编程序使用Intel语法,并且数字存储为Little Endian。

lds r16, number1 ; low byte of number1
lds r17, number2 ; low byte of number2
add r16, r17 ; number1 += number2

lds r17, number1+1 ; high byte of number1
lds r18, number2+1 ; high byte of number2
adc r17, r18 ; add the high bytes including the carry flag generated by the "add" instruction above

因此,结果存储在r17:r16中,例如r17中的高字节和r16中的低字节。

答案 2 :(得分:1)

您的数据表来自this链接addadc。正如我上面提到的,也许您需要使用程序内存加载,ldm来获取您的数字。

基本上:



ldi r0, number1 ; get low address of number 1 in a register.
ldm r16, r0+    ; low-byte of number 1 - inc pointer after each read with r0+
ldm r17, r0+    ; high-byte of number 1
ldm r18, r0+    ; low-byte of number 2
ldm r19, r0+    ; high-byte of number 2

add r16, r18    ; add low bytes
adc r17, r19    ; add hi-bytes with carry

; r16/r17 now holds the sum of the number1 and number2 as a 16-bit number.  
; Store to RAM or whatever you want with them.
;  Note, you may have to push/pop registers depending on your system requirements...

上面的代码不起作用,有一个有效的例子......

如果我使用post-increment ldm命令正确理解上下文,并且所有寄存器都是8位。

答案 3 :(得分:0)

ldi temp, low(number1)
sts number1, temp
ldi temp, high(number1)

符号“number1”具有地址的值,而不是该地址的内容。 因为你已经将“number1”放在了.ORG RAMSTART,那可能是0100 Hex low(number1)等于00,high(number1)等于01

如果您想要地址“number1”的CONTENTS,则必须先将地址输入a 16位地址寄存器,例如Z寄存器=(R30,R31)由以下

组成

LDI R30,HIGH(number1) LDI R31,LOW(number1)

现在,Z寄存器可用于通过以下方式处理地址“number1”中的VALUE:

LD R16,Z + LD R17.Z

现在你在R16,R17中有16位值 现在你必须对“number2”

做同样的事情

LDI R30,HIGH(number2) LDI R31,LOW(number2) LD R18,Z + LD R19.Z

现在你在R18,R19

中有第二个16位数字

现在将它们与LSB中的进位一起添加到MSB

ADD R19,R17;首先添加LSB ADC R18,R16;然后用进位位

添加MSB

答案现在在R18,R19

结论:AVR有一个非常粗糙,低效的指令集。它有一个优于8051的优点:也就是说,堆栈可以在RAM中的任何位置,这允许您运行多个进程,每个进程都有自己的堆栈。 但总的来说,所有哈佛架构处理器SUCK都与冯诺依曼架构相比。 如果只是,请上帝,我希望,有人制造了基于8085或Z80的微控制器,带有片上RAM和FLASH,所有引脚都可以自由作为I / O端口!