Search code examples
assemblyemu8086

Adding two three-word numbers in assembly


This is what I have done so far:

.MODEL SMALL
.STACK 64 
.DATA
X DW 5463h,0F8A8h,0D37Eh
Y DW 87DEh,3408h,92C2h
Result DW 3 DUP(0) ;Trying to add X, Y with the result being here.

.Code
MAIN PROC FAR 
MOV AX,@Data
MOV DS,AX 

;Adding X,Y:
;Getting Pointers Ready
LEA SI,X
LEA DI,Y
LEA BP,Result
MOV CX,3 ; Counter
CLC ;Clearing the carry
PushF ;We don't want the flag to be affected from the next two operations
;Looping three times to Add Word by Word 
WordAdd:
MOV AX,[SI+4] ;We will iterate from the least significant word (4) to the most significant word (0)
MOV BX,[DI+4]
PopF ;Retaining the flag register
ADC AX,BX
PushF
MOV [BP+4],AX
Sub BP,2
Sub SI,2
Sub DI,2
Loop WordAdd

MOV Ax,[BP]
MOV BX,[BP+2]
MOV CX,[BP+4]

MAIN ENDP 
END MAIN

For some reason AX, BX, CX are all 0000 in the end, but I cannot figure out why, even though I made sure that addition is performed correctly and put in AX each time through debugging.


Solution

  • Your code correctly computes the sum and stores it at the three words at Result, in your unusual mixed-endian order. However, keep an eye on the address in BP: you start it pointing to Result and decrement it by 2 on each iteration of the loop. Since you store words in your loop to [BP+4] you get the correct ones, but after the loop BP points to Result-6. So your loads into AX, BX, CX are taken from Result-6, Result-4, Result-2 respectively, which are not where the sum was stored.

    Some more general suggestions:

    • Your current design needs all sorts of magic offsets like [BP+4], [BP+6], etc, scattered throughout the code. These all depend on your array size, so you're effectively hardcoding that size in about 10 places. Think of the pain when you want to modify your program to add four-word numbers instead, or heaven forbid, a length to be determined at runtime. So you might think about designs that would avoid that. For instance, if you started with BP pointing to the last element instead of the first.

    • As Brendan says, your mixed-endian word order is unconventional and would likely confuse other programmers. Reversing the order would also simplify your code in that you could go through your arrays forward instead of backward.

    • A sequence like MOV BX,[DI+4] / ADC AX,BX is redundant when you can simply do ADC AX, [DI+4]. The CPU designers went to a lot of trouble to make every instruction usable with one memory operand; might as well take advantage.

    • LEA SI, X could be replaced by MOV SI, OFFSET X which does the same thing but uses one byte less. The same for your other LEAs that just load a constant address.

    • Remember that memory references using BP are implicitly relative to the stack segment SS. That's fine for a SMALL model where DS and SS are equal, but should you switch code models, you'll wonder why your code is not writing to Result even though BP "obviously" points to it.

    • You are using four different registers in your loop (BP, SI, DI, CX) which are all basically just keeping track of the loop index. See if you can get this down to one. You can have a single register used as an offset into all the arrays by doing something like MOV AX, [X+BX] MOV DX, [Y+BX].

    • The LOOP instruction is a bad habit if you're eventually going to move to working with modern x86 CPUs, as it's poorly optimized and its use is discouraged. Doing the decrement and conditional jump yourself is actually more efficient on such machines, and it also gives you the freedom to use any register instead of being tied to CX.

    • Likewise, the PUSHF/POPF trick is also a bad habit, as these instructions are quite expensive on modern CPUs since they potentially manipulate the interrupt flag. Try to design the rest of your loop so that it leaves the carry flag intact between iterations. The INC and DEC instructions are nice here because they don't modify it; loops like this are exactly why they were designed that way.

    • Capitalize your mnemonics and register names consistently. Some people like all caps, some people like all lower case, but nobody likes mixed case.