0

I wrote an assembly code to sum five numbers. The final value is then stored in the memory.

dtseg    segment
data     dw       27345,28521,29533,30105,32375
sum      dw       ?  
MSG1     DB "The sum is : $"  
dtseg    ends
;---------------------
cdseg    segment
main     proc     far
     assume   cs:cdseg,ds:dtseg,ss:stseg
     mov      ax,dtseg
     mov      ds,ax
     clc                       ; clear the carry
     mov      si,offset data   ; first location of data
     mov      cx,04            ; setting the counter
     mov      ax,0             ; clear ax
     mov      bx,ax            ; clear bx
back:add      ax,[si]          ; the first round: 0+27345
     adc      bx,0             ; if there is a carry, add that to bx
     inc      si               ; two inc because traversing words
     inc      si
     dec      cx               ; count down
     jnz      back             ; do that for other numbers
     mov      sum,ax           ; the final value
     mov      sum+2,bx         ; the carries are stored in bx

     lea      dx,MSG1          ; trying to display the result
     mov      ah,09h
     int      21h  
     mov      ah, 4cH          ; return to DOS
     int      21h
main     endp
cdseg    ends  
         end      main

I followed the example based on this topic, however it doesn't work in emu8086

Community
  • 1
  • 1
mahmood
  • 23,197
  • 49
  • 147
  • 242
  • You have first to convert `sum` into a ASCII string. Look at [this example](http://stackoverflow.com/a/23682807/3512216) – rkhb Oct 11 '15 at 07:45
  • Do you want to output a 32-bit value? – rkhb Oct 11 '15 at 07:50
  • I updated the post. Although there are some similarities between my question and the example, but mine is only a snippet which is better to follow – mahmood Oct 11 '15 at 07:58
  • You should be providing us a [Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve) – Michael Petch Oct 11 '15 at 08:00
  • `sum dw ? ` defines a WORD (= 2 bytes). With `mov sum+2,bx ` you presumably overwrite the first two bytes of `MSG1`. Again: Do you want to output a 32-bit value (DWORD)? How do you set `AX` and `BX`? – rkhb Oct 11 '15 at 08:02
  • 1
    Seems to me that you should be using `sum dd ? ` (a double word) – Michael Petch Oct 11 '15 at 08:09
  • @Michael Petch: Maybe but I wanted to work with `adc` and smaller registers to better understand carries – mahmood Oct 11 '15 at 08:12
  • `DW` stands for **d**ata **w**ord (some say "define word). For a 32-bit value in emu8086 it is appropriate to define two words. I will make an example. You want to have the sum of all words in `data`, right? – rkhb Oct 11 '15 at 08:13
  • Yes, but as you can see I want to manually store in SUM and SUM+2. Think that this is a start point for implementing big numbers.... – mahmood Oct 11 '15 at 08:14
  • The problem is that in order to store your total in bx:ax to memory you need 32 bits of space (a double Word) or two separate words in emu8086 . As @rkhb pointed out you are overwriting the first word of the string after _sum_. – Michael Petch Oct 11 '15 at 08:14
  • @rkhb providing a working answer isn't my first choice because this doesn't show any effort in trying to convert the number to a string. And the previously linked question can be adapted for just that. This is basically a duplicate of every "I need to output a number, but int 21h doesn't work" question on SO. – Michael Petch Oct 11 '15 at 08:19
  • I can not understand why i have to follow that link (which mine has been set to duplicate). I think there is much easier way to do that. But I don't know! – mahmood Oct 11 '15 at 08:27
  • There isn't an easier way to do it, which is likely why your professor has given you this challenge (adding the numbers is half the challenge). If we just keep providing code to do it you won't learn a valuable lesson in number conversion, use of division, use of remainder etc. The other link can be easily adapted to exactly what you need in emu8086. But you'll get lucky because @rkhb will likely do your homework for you (which isn't what SO is suppose to be about) – Michael Petch Oct 11 '15 at 08:34
  • I'd recommend reading this StackOverflow sister site article to students seeking [homework help](http://meta.programmers.stackexchange.com/questions/6166/open-letter-to-students-with-homework-problems) and why people answering shouldn't just give the answers. – Michael Petch Oct 11 '15 at 08:39

1 Answers1

3

This example shows you how to convert a WORD value in AX to a string and output it. You want to convert a DWORD value to a string. In your case you can use the advantage of DIV dividing a DWORD in the registers DX:AX. In the example DX is set to 0, so the first idea is to remove the line xor dx, dx. But you need DX just for the first time, then you must clear it, because it holds the remainder after the DIV. The trick is to perform the clearance after the div instead before it. So it will be used for the first time and cleared for every repetition.

dtseg    segment
data     dw 27345,28521,29533,30105,32375   ; Sum: 147879

sum      dw  ?, ?               ; two WORD = one DWORD
MSG1     DB "The sum is : $"
DECIMAL  db "0000000000$"       ; space for the result
dtseg    ends
;---------------------
cdseg    segment
main     proc     far
     assume   cs:cdseg,ds:dtseg,ss:stseg
     mov      ax,dtseg
     mov      ds,ax
     clc                       ; clear the carry

     mov      si,offset data   ; first location of data
     mov      cx,5             ; setting the counter
     mov      ax,0             ; clear ax
     mov      bx,ax            ; clear bx
back:add      ax,[si]          ; the first round: 0+27345
     adc      bx,0             ; if there is a carry, add that to bx
     inc      si               ; two inc because traversing words
     inc      si
     dec      cx               ; count down
     jnz      back             ; do that for other numbers

     mov      sum,ax           ; the final value
     mov      sum+2,bx         ; the carries are stored in bx

     call mem_to_dec

     lea      dx,MSG1          ; trying to display the result
     mov      ah,09h
     int      21h
     lea      dx,DECIMAL          ; trying to display the result
     mov      ah,09h
     int      21h

     mov      ah, 4cH          ; return to DOS
     int      21h
main     endp

mem_to_dec proc
    mov ax, [sum]
    mov dx, [sum+2]

    mov bx, 10                  ; divisor
    xor cx, cx                  ; CX=0 (number of digits)

    @First_Loop:
        div bx                  ; DX:AX / BX = AX remainder: DX
        push dx                 ; LIFO
        inc cx                  ; increment number of digits
        xor dx, dx              ; Clear DX for the next DIV
        test  ax, ax            ; AX = 0?
        jnz @First_Loop         ; no: once more

        mov di, OFFSET DECIMAL  ; target string DECIMAL
    @Second_Loop:
        pop ax                  ; get back pushed digit
        or ax, 00110000b        ; to ASCII
        mov byte ptr [di], al   ; save AL
        inc di                  ; DI points to next character in string DECIMAL
        loop @Second_Loop       ; until there are no digits left

        mov byte ptr [di], '$'  ; End-of-string delimiter for INT 21 / FN 09h
        ret
mem_to_dec endp

cdseg    ends
         end      main

There will be an issue with DIV, if the result don't fit into the AX register. Then you get an overflow error.

Community
  • 1
  • 1
rkhb
  • 14,159
  • 7
  • 32
  • 60
  • Any reason to prefer `inc cl` (2 bytes) over `inc cx` (1 byte) ? – Sep Roland Oct 11 '15 at 13:39
  • 1
    @mahmood Please note that this exellent solution is in fact a special case where the dividend must not be any greater than 655359. With your 5 numbers (sum = 147879) it will be no problem, but don't use this as a general solution to convert a dword number into text. – Sep Roland Oct 11 '15 at 13:47