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
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.
Related
I have got a project to do as a student and i was about to finish him when i occured a strange thing - when i running my program via the cv debugger i get diffrent result than by running it simply....
Here is my code, he suppose to do this thing :
.model small
.stack 100h
.data
.code
time proc
mov ah, 02ch
int 21h
mov bl, ch
call printit
ret
time endp
printit proc
mov al, bl
aam ; divide by 10: quotient in ah, remainder in al (opposite of DIV)
add ax, "00"
xchg al, ah
mov dx, ax
mov ah, 02h
int 21h
mov dl, dh
int 21h
ret
printit endp
print4register proc
mov cx, 0
LOOP1:
inc cx
cmp cx, 5
jge ENDLOOP
mov dx, 0
mov bx, 16
div bx
cmp dx, 9
jg ABCDE
add dl, '0'
push dx
jmp LOOP1
ABCDE:
sub dl, 10
add dl, 'A'
push dx
jmp LOOP1
ENDLOOP:
pop dx
mov ah, 02h
int 21h
pop dx
int 21h
pop dx
int 21h
pop dx
int 21h
ret
print4register endp
date proc
mov ah, 02ah
int 21h
mov bl, dl
call printit
ret
date endp
start:
mov cl, byte ptr ds:[80h]
mov bx, 82h
mov ax, ds:[bx]
cmp al, 'T'
je TIMET
cmp al, 'D'
je DATED
cmp al, 'I'
je INTI
jmp FINISH
TIMET:
inc bx
mov ax, ds:[bx]
cmp al, 'I'
je TIMEI
jmp FINISH
TIMEI:
inc bx
mov ax, ds:[bx]
cmp al, 'M'
je TIMEM
jmp FINISH
TIMEM:
inc bx
mov ax, ds:[bx]
cmp al, 'E'
je TIMEE
jmp FINISH
TIMEE:
call time
DATED:
inc bx
mov ax, ds:[bx]
cmp al, 'A'
je DATEA
jmp FINISH
DATEA:
inc bx
mov ax, ds:[bx]
cmp al, 'T'
je DATET
jmp FINISH
DATET:
inc bx
mov ax, ds:[bx]
cmp al, 'E'
je DATEE
jmp FINISH
DATEE:
call date
INTI:
inc bx
mov ax, ds:[bx]
cmp al, 'N'
je INTN
jmp FINISH
INTN:
inc bx
mov ax, ds:[bx]
cmp al, 'T'
je INTT
jmp FINISH
INTT:
inc bx
mov ax, ds:[bx]
sub al, '0'
add al, al
add al, al ; mul al, 4
mov di, 0
mov ah, 0
add di, ax
mov ax, 0h
mov es, ax
mov ax, es
mov si, es:[di]
mov di, es:[di + 2]
mov ax, di
call print4register
mov dl, ':'
mov ah, 02h
int 21h
mov ax, si
call print4register
FINISH:
mov ah, 4ch
int 21h
end start
The task:
Write the program "DO_ALL" that accepts a single parameter from the
MS-DOS command line.
i.e. type in the dosbox:
C:> DO_ALL DATE
or
C:> DO_ALL TIME
to run your program with the command "DATE" or "TIME" respectively.
The DO_ALL program should figure out the appropriate command and
perform as
follows:
DATE – present the date (use int21/2A) – present only the day
TIME – present the time (use int21/2C) – present only the hour
INTx (here x is 1 digit, for example INT4 or INT0) – print the CS:IP
of the ISR
of interrupt number x.
Hint: use the information in the PSP to figure out the command (The
last 2
fields)
Unfortuently, as I said, when i run it like that - cv DO_ALL INT4 i get this result - 043F:038E ( after running the program in the debugger ) .
And when I run it like that - DO_ALL INT4 i get this result - 0070:0008
Someone know what to do :((
My dos running results
I have a function "swapByRef" that works in this code (this code just checks if the function swaps the values).
MODEL small
STACK 10h
DATA SEGMENT
a dw 12h
b dw 0A9h
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
start:
mov ax, DATA
mov ds, ax
push offset a ;push to the stack the adress of the variable a
push offset b ;push to the stack the adress of the variable b
call swapByRef
exit:
mov ax, 4c00h
int 21h
swapByRef proc
mov bp, sp
mov bx, [bp + 2]
mov ax, [bx]
mov si, [bp + 4]
mov cx, [si]
mov [bx], cx
mov[si], ax
ret 4
swapByRef endP
CODE ENDS
END start
But in my code (the bubble sort code) the procedure doesn't swap the values in the array and the array does not get sorted.
MODEL small
STACK 100h
DATA SEGMENT
ARR dw 9,5,7,3,8
len dw 5
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
start:
mov ax, DATA
mov ds, ax
mov bx, offset ARR
sorting:
mov ax, len
dec ax
cmp bx, ax
je redo
mov ax, ARR[bx]
mov dx, ARR[bx+ 2]
cmp al, ah
jg swap
jmp continue
swap:
push offset [ARR + bx]
push offset [ARR + bx + 2]
call swapByRef
continue:
inc bx
jmp sorting
redo:
cmp len, 0
je exit
mov ax, len
dec ax
mov len, ax
xor bl, bl
jmp sorting
exit:
mov ax, 4c00h
int 21h
swapByRef proc
mov bp, sp
mov bx, [bp + 2]
mov ax, [bx]
mov si, [bp + 4]
mov cx, [si]
mov [bx], cx
mov[si], ax
ret 4
swapByRef endP
CODE ENDS
END start
I've tried to debug and still I couldn't find the problem in my code...
Any help will be awesome, thanks.
mov bx, offset ARR
...
mov ax, ARR[bx]
mov dx, ARR[bx+ 2]
You're adding the offset to the array twice! You need to initialize BX=0.
mov ax, ARR[bx]
mov dx, ARR[bx+ 2]
cmp al, ah
jg swap
jmp continue
swap:
You've read the elements in AX and DX. Then also compare AX and DX.
You can also write it shorter like this:
mov ax, ARR[bx]
cmp ax, ARR[bx+2]
jng continue
swap:
Given that the array contains words and that BX is an offset within the array, you need to change BX in steps of 2. Write add bx, 2 instead of inc bx.
This also means that it's best to set len dw 10 and modify it in steps of 2 using sub word ptr len, 2.
swapByRef proc
mov bp, sp
mov bx, [bp + 2]
mov ax, [bx]
mov si, [bp + 4]
mov cx, [si]
mov [bx], cx
mov[si], ax
ret 4
Your swapByRef proc destroys a lot of registers. Especially loosing BX is problematic!
This is a general solution to not clobber registers. Optimize as needed.
swapByRef proc
push bp
mov bp, sp
push ax
push bx
push cx
push si
mov bx, [bp + 4]
mov ax, [bx]
mov si, [bp + 6]
mov cx, [si]
mov [bx], cx
mov [si], ax
pop si
pop cx
pop bx
pop ax
pop bp
ret 4
I'm trying to scroll 1 line down then up but
a) I don't know how to test this code
b) I'm not sure which interrupt to use for "when a key is pressed"
I'd be much grateful for your help
Here's my code :
Data_segment_name segment para
firstline db 160 dup(0)
Data_segment_name ends
Stack_segment_name segment para stack
Stack_segment_name ends
Code_segment_name segment
Main_prog proc far
assume SS:Stack_segment_name,CS:Code_segment_name,DS:Data_segment_name
mov AX,Data_segment_name ; load the starting address of the data
mov DS,AX ; segment into DS reg.
;code scroll down (clear first line) then scroll back up(restore cleared line)
mov es,ax ;save first line
lea di,firstline
mov ax,0b800h
mov ds,ax
mov ax,0
mov si,ax
cld
mov cx,80
rep movsw ;save ends
;now let's scroll down :)
mov ax,0b800h
mov es,ax
mov ax,0
mov di,ax
mov ax,160
mov si,ax
cld
mov cx,24*80
rep movsw
;now let's scroll up :)
int 21h ;check
mov ax,160*24
mov si,ax
mov ax,160*25
mov di,ax
std
mov cx,24*80
rep movsw
;restore first line
mov AX,Data_segment_name ; load the starting address of the data
mov DS,AX ; segment into DS reg.
lea si,firstline
mov ax,0
mov di,ax
cld
mov cx,80
rep movsw
mov ax,4c00h ; exit program
int 21h
Main_prog endp
Code_segment_name ends
end Main_prog
Ad a):
The test tool is called "debugger". I recommend Turbo Debugger (google for it).
Ad b):
Ralf Brown's interrupt list and TechHelp are good references. At a glance: Int 10h is for video, Int 16h is for keyboard, Int 21h is for MS-DOS.
You should switch to the simplified segment directives .CODE, .DATA, .STACK and to procedural programming PROC, ENDP. When your project grows, it will help to keep track of it.
Example:
.MODEL small
.STACK 1000h
.DATA
firstline db 160 dup(0)
.CODE
save_firstline PROC
push ds
mov ax, ds
mov es, ax
lea di, firstline
mov ax, 0b800h
mov ds, ax
mov ax, 0
mov si, ax
mov cx, 80
rep movsw
pop ds
ret
save_firstline ENDP
restore_firstline PROC
lea si, firstline
mov ax, 0b800h
mov es, ax
mov ax, 0
mov di, ax
mov cx, 80
rep movsw
ret
restore_firstline ENDP
scroll_up PROC
call save_firstline
mov ah, 6 ; http://www.ctyme.com/intr/rb-0096.htm
mov al, 1 ; number of lines to scroll
mov bh, 0 ; attribute
mov ch, 0 ; row top
mov cl, 0 ; col left
mov dh, 25 ; row bottom
mov dl, 80 ; col right
int 10h
ret
scroll_up ENDP
scroll_down PROC
mov ah, 7 ; http://www.ctyme.com/intr/rb-0097.htm
mov al, 1 ; number of lines to scroll
mov bh, 0 ; attribute
mov ch, 0 ; row top
mov cl, 0 ; col left
mov dh, 25 ; row bottom
mov dl, 80 ; col right
int 10h
call restore_firstline
ret
scroll_down ENDP
main PROC
mov ax, #data
mov ds, ax
waitForKey: ; http://webpages.charter.net/danrollins/techhelp/0229.HTM
mov ah, 1
int 16h
jnz gotKey ; jmp if key is ready
jmp waitForKey ; loop back and check for a key
gotKey:
mov ah, 0 ; key is ready, get it
int 16h ; now process the key
cmp ah, 48h ; <UP>
jne #F
call scroll_up
jmp waitforKey
##:
cmp ah, 50h ; <DOWN>
jne #F
call scroll_down
jmp waitForKey
##:
cmp al, 1Bh ; <ESC>
jne waitForKey
mov ax, 4C00h
int 21h
main ENDP
END main
I have a program that compiles correctly with zero error or warning but does not display the output I cannot guess the reason for no output
.model small
.data
a dw 1234H
b dw 0100H
.code
Process:
MOV AX, #data
MOV DS, AX
Mov AX, a
MOV BX, b
SUB AX, BX
MOV CH, 04H
MOV CL, 04H
MOV BX, AX
X: ROL BX, CL
MOV DL, BL
AND DL, 0FH
CMP DL, 09
JBE Y
ADD DL, 07
Y: ADD DL, 30H
INT 21H
DEC CH
JNZ X
MOV AH, 4CH
INT 21H
END Process;
If you intend to write characters one at a time to STDOUT then DL should contain the character and AH must be set to 02H before you invoke INT 21H. So,
Y: ADD DL, 30H
MOV AH, 02H
INT 21H
You can also set AH to 02H before the loop starts, saving on the number MOV instructions.
i wrote this code and think for it about 5 hours;
However i stuck in sorting part:
its begin to loop and never stop !
where did i wrong ???
IT SEEMS that the array didnt get the numbers correctly.
can any one help please ?
page 110,100
Title 'decimal sorting'
Data_here segment
A DD Dup 20(?)
msg1 DB 'Enter a maximum 6 digits number : ',0DH,0AH,'$'
msg2 DB 0DH,0AH,'The sorted results are : ',0DH,0AH,'$'
Data_here Ends
Stack_here segment
DW 10 DUP(?)
Stack_here Ends
Code_here segment
Assume CS:code_here , DS:Data_here ,SS:Stack_here
Main Proc near
mov AX,Data_here
mov DS,AX
mov AX,Stack_here
mov SS,AX
Call decimal_input
call sorting
call decimal_output
mov AH,4CH
int 21H
main Endp
decimal_input proc near
PUSH A
mov AH,09H
Lea DX,msg1
int 21H
mov CH,20
next_number:
mov BH,6
mov DX,0
mov si,4
next_digit:
mov AH,07H
int 21H
CMP AL,0DH
JNE check_digit
CMP BH,6
JE next_digit
DEC CH
JZ end
mov DX,0DH
mov AH,02H
int 21H
mov DX,0AH
Int 21H
jmp next_number
check_digit:
cmp AL,30H
JB next_digit
cmp AL,39H
JA next_digit
mov AH,02H
mov DL,AL
int 21H
SUB AL,30H
SHL DX,4
ADD DL,AL
DEC SI
JZ save
DEC BH
JNZ next_digit
jmp remain
save:
mov A[DI],DX
SHL A[DI],8
add si,4
DEC BH
jmp next_digit
remain:
ADD byte ptr A[DI],DL
mov DX,0DH
mov AH,02H
int 21H
mov DX,0AH
INT 21H
INC DI
DEC CH
JNZ next_number
end:
pop A
RET
decimal_input ENDp
sorting proc near
Push A
mov SI,DI
check:
mov AX,word ptr A[SI]
mov BX,word ptr A[DI+2]
CMP AX,BX
JA change
JE extra_check
add SI,2
continue:
add DI,2
CMP DI,38
JA finish
JB check
extra_check:
mov CX,word ptr A[DI+1]
mov DX,word ptr A[DI+3]
cmp CX,DX
JNA continue
mov word ptr A[DI+1],DX
mov word ptr A[DI+3],CX
jmp continue
change:
xchg AX,BX
mov CX,word ptr A[DI+1]
mov DX,word ptr A[DI+3]
xchg CX,DX
mov word ptr A[DI],AX
mov word ptr A[DI+1],CX
mov word ptr A[DI+2],BX
mov word ptr A[DI+3],DX
jmp continue
finish:
Add sp,2
cmp Sp,40
JE ending
mov DI,SP
jmp check
ending:
POP A
RET
sorting ENDP
decimal_output proc near
PUSH A
mov AH,09H
lea DX,msg2
INT 21H
next_no:
mov DL,0
mov AL,0
mov AH,0
next:
CMP AL,0
JE next1
mov DL,byte ptr A[DI]
ADD DL,30H
mov AL,1
int 21H
next1:
inc DI
inc AH
cmp AH,8
JB next
CMP DI,80
JA THE_END
mov DX,0DH
mov AH,02H
int 21H
mov DX,0AH
int 21H
jmp next_no
THE_END:
pop A
RET
decimal_output ENDp
code_here Ends
END MAIN
I think your problem might be here
Add sp,2
cmp Sp,40
You are using sp as a loop counter, but you never initialize it. Additionaly I also don't understand why you are using sp in the first place. Of course it is theoretically possible, but then you would have to restore it before you return. When your proc returns it will screw up, because the stack pointer is corrupted. So you shouild use some other register or a memory variable (bp is not used in your code).
And I would strongly recommend to reformat your code, to make it more readable (when I looked at it I formatted it like this which makes it better readable):
sorting proc near
Push A
mov SI,DI
check:
mov AX,word ptr A[SI]
mov BX,word ptr A[DI+2]
CMP AX,BX
JA change
JE extra_check
add SI,2
continue:
add DI,2
CMP DI,38
JA finish
JB check
...