I'm working with a ATmega128 microcontroller and supposedly need to add two 16-bit numbers. I'm using AVR Studio and this is what I got so far:
.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
This is not far from the first time I'm using any type of assembly, I know I'm doing something wrong, but can't seem to figure out what. Am I missing the carry flag?
Back to gradeschool with pencil and paper. If I want to add 1234 and 5678
1234
+ 5678
======
4+8 is 2 carry the 1
1
1234
+ 5678
======
2
and so on
00110 <-- carry bits
1234 <-- first operand
+ 5678 <-- second operand
======
6912
the carry bit above the ones column is significant, it is called the carry in, and the carry bit that leaves the leftmost column is carry out.
What if I only had paper wide enough to add two columns at a time?
110
34
+ 78
======
12
I start with the two lower sets of digits, and I require a zero as a carry in. I get a result 12 with a carry out.
Now I take that carry out, use it as a carry in for the next two digits. This adder I must be able to take a carry out from a prior add and use it as the carry in for this add.
001
12
+ 56
====
69
When all is said and done I get 69 and 12, put those together I get 6912 but didnt need a full 4 digit adder to get there. You can repeat this forever or until you run out of memory, registers or clock cycles.
The avr may have other ways to solve the problem, but most processors at least have two forms of add and two forms of subtract so that you can cascade the adder to be as wide as you need. Examine the instruction set for the avr and what is going on above should jump out at you.
EDIT:
A C example might help...(switching to hex)
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:
I hope this is not a homework assignment...
ldi r20,0x12
ldi r21,0x34
ldi r22,0x56
ldi r23,0x78
add r21,r23
adc r20,r22
result is in r20 high byte, and r21 low byte
if you need to read from ram there are many ways, this assumes the 16 bit numbers are little endian
lds r0,0x100
lds r1,0x101
lds r2,0x102
lds r3,0x103
add r0,r2
adc r1,r3
r0 low half of result, r1 upper half.
or use one of the x,y,or z pointer registers
;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