L315
L315

Reputation: 11

Assembly- addition of 2 numbers taken as input

Need to write a program that takes in two numbers as input and prints the sum of them. Not sure where I'm going wrong here. I think the division might be a little funky but am really struggling with why my output is not correct. Ex. of output: input 10 and 11 - output 22. I appreciate any help!

       .model small
;-----------------------------------------------------
        .stack  64
;-----------------------------------------------------  
        .data
PR      DB      'ENTER: ','$'
Num1    Label   Byte
Max1    DB      3 ; need to hit atmost 3 keys when entering- 2 digits and the enter key
Act1    Db      ?
N1      DB      4 DUP ('$')
Num2    Label   Byte
Max2    DB      3 ; need to hit atmost 3 keys when entering- 2 digits and the enter key
Act2    Db      ?
N2      DB      4 DUP ('$')
Hold    DW      ?
Res     DB      3 DUP ('$')
msg     Db      " Result is $"
;-----------------------------------------------------
        .code
MAIN    proc    FAR
        mov     AX,@data        ; Initialize segment
        mov     DS,AX           ; registers

        call    CLEAR
        call    SET_CURSOR
        call    REQUEST_INPUT
        call    GET_INPUT1
        call    SET_CURSOR2
        call    REQUEST_INPUT
        call    GET_INPUT2
        call    SET_CURSOR3
        call        Convert


        mov     AX,4C00h        ; Exit to DOS
        int     21h
MAIN    endp
;-----------------------------------------------------
CLEAR   proc    NEAR
        mov     AX, 0600H
        mov     BH, 71H
        mov     CX, 0000H
        mov     DX, 184FH
        int     10H
        ret
CLEAR   endp

;-----------------------------------------------------
SET_CURSOR      proc    NEAR
        mov     AH, 02H
        mov     BH, 0           ;sets color of backround 
        mov     DH, 5
        mov     DL, 10
        int     10H
        ret
SET_CURSOR      endp
;-----------------------------------------------------
REQUEST_INPUT   proc    NEAR
        mov     AH, 09H
        lea     DX, PR
        int     21H 
        ret
REQUEST_INPUT   endp

;-----------------------------------------------------
GET_INPUT1       proc    NEAR
        mov     AH, 0AH
        lea     DX,Num1
        int     21H
        mov     BH, 00
        mov     BL, Max1
        mov     N1[BX],'$'
        ret
GET_INPUT1       endp
;-----------------------------------------------------
GET_INPUT2      proc    NEAR
        mov     AH, 0AH
        lea     DX,Num2
        int     21H
        mov     BH, 00
        mov     BL, Max2
        mov     N2[BX],'$'
        ret
GET_INPUT2       endp
;-----------------------------------------------------          
Convert         proc    NEAR
                mov     BX, 0
                    mov     AH, 00h
                mov     Al, N1[BX]   ; Get a character
                Sub Al, 48 ; to get decimel value from character 
                Mov Bx, 10
                Mul Bx                                                  
                mov Cl, Al ; Result of multiplication stored in Al
                 mov     BX, 1
                    mov     BH, 00h
                mov     Bl, N1[BX]   ; Get a character
                Sub BL, 48
                Add Cl, Bl ; Add first digit and second digit
                mov     BX, 0
                    mov     CH, 00h
                mov     Al, N2[BX]   ; Get a character
                    Sub Al, 48 ; to get decimel value from character
                Mov Bx, 10
                Mul Bx                                      
                Mov Bl, Al ; Result of multiplication stored in Al
                 mov     BX, 1
                    mov     BH, 00h
                mov     AL, N2[BX]   ; Get a character
                Sub Al, 48 ;to get decimel value from character 
                Add Al, Bl ; Add first and second digit
                Add Cl, Al ; Add number one and number two
                Mov Ah, 0; zero out ah before devision 
                Mov Al, Cl
                Mov Cl, 10 
                Div Cl

                Add Al, 48  ;Value of int devision 
                Mov Res[0], Al
                Add AH, 48 ;value of remainder 
                Mov Res[1], AH              
                mov     AH,09h
                lea     DX, msg
                int     21H
                mov     AH,09h
                lea     DX, Res
                int     21H
                ret

Convert         endp                
;-----------------------------------------------------
SET_CURSOR2      proc    NEAR
        mov     AH, 02H
        mov     BH, 0           ;sets color of backround 
        mov     DH, 6
        mov     DL, 10
        int     10H
        ret
SET_CURSOR2     endp
;-----------------------------------------------------  
SET_CURSOR3      proc    NEAR
        mov     AH, 02H
        mov     BH, 0           ;sets color of backround 
        mov     DH, 7
        mov     DL, 10
        int     10H
        ret
SET_CURSOR3      endp                   
;------------------------------------------------------------           




            ;formula ()N1[0]-48)*10 + (N1[1]-48)
            ;same for N2
            ;before printing need to divide result of N1+N2 by 10. the quation is the frist character remainder is the second character- quaotiant will be in AL, Remainder in AH
            ;then need to add 48 before putting them into the array Res
            ;To go back Add Al,48-Mov Res[0], AL


;-----------------------------------------------------------'
                end     MAIN

Upvotes: 0

Views: 3975

Answers (1)

Ped7g
Ped7g

Reputation: 16606

8086 has more than 3 registers (ax, bx, cx in your code reused a lot).

While your code is exercising lot of unneeded re-sets of values, you manage to avoid any clash up till Mov Bl, Al (storing result of N2[0]*10), followed by mov bx,1 overwriting this value.

If you would use debugger, you would probably notice you lost your value.

If you know, you will access for example N2[1], don't bother with bx, just write mov al,[N2+1].

If you do mul bx, you are doing dx:ax = bx * ax (check always documentation for instruction, if you are not sure how it works), in your special case of 2 digit numbers and multiplying by 10, you can just set up al (0-9 value) and do mul bl (10), which will put result into ax (0-90 value), clearing upper 8 bits of ax for you.

And if I'm already tackling on cleaning up code by trying to do only the inevitable, how about removing one mul completely:

If you have numbers x, y stored as x1,x0 and y1,y0, where n = ∑ni*10i, then:
x + y ⇔ x1 * 10 + x0 * 1 + y1 *10 + y0 * 1 ⇔
⇔ 10 * (x1 + y1) + (x0 + y0)

So in your code you can do:

mov al,[N1+0]  ; ASCII x1
add al,[N2+0]  ; ASCII y1 (no real overflow risk, 8b is enough)
sub al,2*'0'   ; convert from ASCII to value
mov ah,10
mul ah         ; ax = 10 * (x1+y1) (value is 0 to 180)
add al,[N1+1]  ; add ASCII x0 (48-57 value)
add al,[N2+1]  ; add ASCII y0
; max possible AL value = 180 + 57 + 57 = 294
; -> may overflow, but doesn't matter, conversion will "fix" it
sub al,2*'0'   ; convert x0,y0 from ASCII to values
; will "fix" overflow by ignoring AH all the time, keeping it 0
; ax = result here (0 to 188 value = fits to 8 bits)

So it's possible to write that Convert PROC using only ax, thanks to the 2-digit input constraint (this is far from universal addition routine, using actually every bit of that constraint to keep the code very simple and short).

BTW, if you would use the 386+ (32-bit) instruction set, then *10 can be done in two instructions using the LEA instruction, like this:

; eax = 0-9 value
add   eax,eax           ; *2
lea   eax,[eax+eax*4]   ; *5

This avoids mul completely, which used to be slow... with the very latest x86 CPUs actually doing imul eax,eax,10 may be faster, because it's single instruction vs two simple ones, but for many years the two additions (add and lea) were "cheaper" than single mul/imul.

On the original 8086, it would be still faster to do all the adding like this:

; al = 0-9 value
add al,al     ; AL = 2*value
mov dl,al     ; copy 2*value to DL
add al,al     ; AL = 4*value
add al,al     ; AL = 8*value
add al,dl     ; AL = 10*value

than mul bl, which would take about 70-77 clocks to compute on original 8086, the code above needs 4*3+2 = 14 clocks only on original 8086.

Upvotes: 2

Related Questions