0

The code below, is supposed to get 20 user-entered numbers (6 digit numbers or less) and compute the average as well as sorting them, When I set it to get 6 or less numbers, it works fine. But when it is set to get 7-20 numbers, after getting the numbers, it skips the next procedures and someimes runs the GetNum procedure ( The one that gets the numbers from user) again and when it gets 11 numbers, I get this message "PROGRAM HAS RETURNED CONTROL TO THE OPERATING SYSTEM".

ShowMsg macro msg
mov ah, 09h
mov dx, offset msg
int 21h
endm

NewLine macro
mov ah, 02h
mov dl, 0ah
int 21h
mov dl, 0dh
int 21h
endm


data segment
sum   dd 0
num   dd 0
ave   dd 0
array dd 20 dup(0)
msg1  db 'Enter 20 numbers:', '$'
msg2  db 0dh,0ah,'Average: ', '$'
temp  dd ?
data ends 

stack segment
dd 100 dup(?)
stack ends

code segment
assume cs:code, ds:data, ss:stack
Main Proc Far

    mov ax, data
    mov ds, ax
    mov ax, stack
    mov ss, ax

    ;Printing first message.
    ShowMsg msg1

    call GetNum

    call Average

    call Sort

    call Print

    mov ah, 4ch
    int 21h

Main endp

proc GetNum  

    mov bp, 0
    mov ch, 20

    NextNumber:
    NewLine

    mov cl, 6
    mov word ptr num, 0
    mov word ptr num+2, 0

    GetChar:    
    mov ah, 07h
    int 21h

    cmp al, 0dh
    jz Flag

    cmp al, 30h
    jb GetChar

    cmp al, 39h
    ja GetChar

    mov ah, 02h
    mov dl, al
    int 21h

    sub al, 30h

    mov bl, al
    mov di, 10
    mov ax, num
    mul di

    mov num, ax
    push dx

    mov ax, num+2
    mul di

    mov num+2, ax
    pop dx
    add num+2, dx

    mov bh, 0
    add num, bx
    adc word ptr num+2, 0

    dec cl
    jnz GetChar

    Flag:
    mov ax, num
    mov dx, num+2

    mov array[bp], ax
    mov array[bp+2], dx
    add bp, 4 

    add sum, ax
    adc sum+2, dx

    dec ch
    jnz NextNumber

    ret

GetNum endp

proc Average 

    mov bx, 20
    mov dx, 0
    mov ax, word ptr sum+2
    div bx 

    mov word ptr ave+2, ax
    mov ax, word ptr sum
    div bx
    mov word ptr ave, ax

    ShowMsg msg2

    mov cl, 0
    Next1:
    mov bx, 10
    mov dx, 0
    mov ax, word ptr ave+2
    div bx

    mov word ptr ave+2, ax 
    mov ax, word ptr ave
    div bx
    mov word ptr ave, ax

    push dx
    inc cl

    cmp ave, 0
    jnz Next1

    Next2:
    pop dx
    add dl, 30h
    mov ah, 02h
    int 21h

    dec cl
    jnz Next2

    NewLine

    ret

Average endp 

proc Sort 

    mov ch, 20

    OuterFor:
    mov bp, 0

    Cmp1:
    mov ax, array[bp+2] 
    mov bx, array[bp+6]

    cmp ax,bx
    ja Xchange 

    cmp ax,bx
    jz Cmp2

    jmp Next

    Cmp2:
    mov ax, array[bp]
    mov bx, array[bp+4]
    cmp ax, bx
    ja Xchange

    jmp Next

    Xchange:
    mov ax, array[bp]
    mov dx, array[bp+2]
    mov temp, ax
    mov temp+2, dx
    mov ax, array[bp+4]
    mov dx, array[bp+6]
    mov array[bp], ax
    mov array[bp+2], dx
    mov ax, temp
    mov dx, temp+2
    mov array[bp+4], ax
    mov array[bp+6], dx
    Next:
    add bp, 4
    cmp bp, 76
    jnz Cmp1 

    dec ch
    jnz OuterFor

    ret

Sort endp

proc Print 

    mov bp, 0
    C: 
    mov cl, 0
    A:
    mov bx, 10
    mov dx, 0
    mov ax, array[bp+2]
    div bx

    mov array[bp+2], ax 
    mov ax, array[bp]
    div bx
    mov array[bp], ax

    push dx
    inc cl
    mov ax, array[bp]
    mov dx, array[bp+2]
    or ax, dx
    jnz A

    B:
    pop dx
    add dl, 30h
    mov ah, 02h
    int 21h

    dec cl
    jnz B 

    add bp, 4

    NewLine

    cmp bp, 80
    jnz C

    ret
Print endp

code ends
end main
Asnira
  • 313
  • 1
  • 4
  • 9
  • `Enter` isn't a particularly good naming choice, since there's an x86 instruction with the same name. Are you sure that the assembler really expands your macro rather than generating the opcode for the `enter` instruction? (i.e. have you looked at a disassembly of your program?) – Michael May 07 '15 at 13:19
  • I did not know that there is an 'enter' instruction, I renamed the macro but the problem is still here. – Asnira May 07 '15 at 13:36
  • Use a debugger to single step the code. – Jester May 07 '15 at 14:01

1 Answers1

2

The problem lies with these two lines (and possibly similar elsewhere):

mov array[bp], ax
mov array[bp+2], dx

By default, the bp register addresses the stack segment, not the data segment where array is. You must either use another index register, or over ride the segment with

mov ds:array[bp], ax
mov ds:array[bp+2], dx

If it worked with a small number of elements, that was by luck that nothing was corrupted to make a crash or spoil the data.

UPDATE

I would suggest modifying the GetNum proc so you can use bx to index array, instead of bp.

proc GetNum  
mov bx, 0
mov ch, 20

NextNumber:
push bx
NewLine
...
pop bx
mov array[bx], ax
mov array[bx+2], dx
add bx, 4 
...

Similarly with your sorting function - swap the roles of bx and bp. It it better to use bp as a general purpose register and bx as an indexing register.

Weather Vane
  • 33,872
  • 7
  • 36
  • 56
  • I changed the type of my stack from `dd` to `dw`, and now its working fine for 20 numbers, so is it still luck or is it ok to use `bp` ? – Asnira May 07 '15 at 15:32
  • 1
    Don't use BP as a pointer for data variables (as Weather says). By the way, changing the stack from DD to DW is a very interesting discovery to me. – Jose Manuel Abarca Rodríguez May 07 '15 at 15:33
  • 1
    @Asnira Jose is being cheeky: the stack doesn't have a type like that. You mean you changed `array DD` to `array DW`. That's wrong: you need 20 * 4 bytes to store your data. To use `DW` you would have to declare 40 elements not 20, since you store 32 bits values for each element. – Weather Vane May 07 '15 at 15:50
  • I changed `stack segment dd 100 dup(?) stack ends` to `stack segment dw 100 dup(?) stack ends` and its working now. – Asnira May 07 '15 at 16:07
  • 1
    @Asnira it's a pity you didn't find a correct way to solve this. You've fudged your way out of it this time, but you haven't learned the right way of doing it. Next time, are you better equipped? I have updated my answer with some suggestions. – Weather Vane May 07 '15 at 17:23
  • @WeatherVane I got your point, I am not gonna use `bp` as index again. Thanks. – Asnira May 07 '15 at 17:40
  • 1
    You will use `bp` as an index register eventually. Its typical use is to index a *stack frame*, but that's quite different from "borrowing" the bottom of the stack! That's why the default segment for `bp` is the `stack` segment. – Weather Vane May 07 '15 at 17:42
  • @WeatherVane Why would u index a stack when u can only access the top of it? – Asnira May 07 '15 at 17:54
  • 1
    There is plenty of material out there for the curious, and to program well you have to be that. Here is one SO question about stack frames, there are others! http://stackoverflow.com/questions/579262/what-is-the-purpose-of-the-frame-pointer – Weather Vane May 07 '15 at 18:33