Sorting a list of ten numbers with selection sort in assembly language - sorting

sorting a list of ten numbers with selection sort in assembly language.
How does i convert this bubble sort method into selection sort method
`[org 0x0100]
jmp start
data: dw 60, 55, 45, 50, 40, 35, 25, 30, 10, 0
swap: db 0
start: mov bx, 0 ; initialize array index to zero
mov byte [swap], 0 ; rest swap flag to no swaps
loop1: mov ax, [data+bx] ; load number in ax
cmp ax, [data+bx+2] ; compare with next number
jbe noswap ; no swap if already in order
mov dx, [data+bx+2] ; load second element in dx
mov [data+bx+2], ax ; store first number in second
mov [data+bx], dx ; store second number in first
mov byte [swap], 1 ; flag that a swap has been done
noswap: add bx, 2 ; advance bx to next index
cmp bx, 18 ; are we at last index
jne loop1 ; if not compare next two
cmp byte [swap], 1 ; check if a swap has been done
je start ; if yes make another pass
mov ax, 0x4c00 ; terminate program
int 0x21`

The key here is to change your loop. Currently it's swapping adjacent numbers. You need to change it to copy the rightmost element into a register, and shift the pre-existing sorted array to the right until the element you just shifted is greater than or equal to the previously rightmost element you just copied into your register.

Maybe this will be helpfull. I wrote this a long time ago. Realmode intel assembler.
MAIN.ASM
SSTACK SEGMENT PARA STACK 'STACK'
DW 128 DUP(?)
SSTACK ENDS
DSEG SEGMENT PUBLIC 'DATA'
S LABEL BYTE
ARR DB 'IHGFED27182392JASKD1O12312345CBA'
LEN EQU ($-S)
PUBLIC TMP
PUBLIC MIN
TMP DW ?
MIN DW ?
DSEG ENDS
CSEG SEGMENT 'CODE'
ASSUME CS:CSEG, SS:SSTACK, DS:DSEG
EXTRN OUTPUT:NEAR
EXTRN SORT:NEAR
START: MOV AX, DSEG
MOV DS, AX
MOV BX, OFFSET ARR
MOV CX, LEN
CALL OUTPUT
MOV AX, 60
CMP AX, 0
JZ NO_SORT
CMP AX, 1
JZ NO_SORT
MOV BX, OFFSET ARR
MOV CX, LEN
CALL SORT
NO_SORT: MOV BX, OFFSET ARR
MOV CX, LEN
CALL OUTPUT
MOV AH, 4CH
MOV AL, 0
INT 21H
CSEG ENDS
END START
SORT.ASM
DSEG SEGMENT PUBLIC 'DATA'
EXTRN TMP:WORD
EXTRN MIN:WORD
DSEG ENDS
CSEG SEGMENT 'CODE'
ASSUME CS:CSEG, DS:DSEG
PUBLIC SORT
SORT PROC; (AX - N, BX - ARRAY ADDRESS, CX - ARRAY LENGTH)
PUSH SI
PUSH DI
PUSH DX
CALL COMPARE_MIN
DEC CX
MOV AX, CX
XOR SI, SI
XOR DI, DI
L1:
PUSH CX
MOV MIN, SI
MOV TMP, DI
INC DI
MOV CX, AX
L2:
MOV DH, BYTE PTR[BX+DI]
PUSH SI
MOV SI, MIN
MOV DL, BYTE PTR[BX+SI]
POP SI
CMP DH, DL
JA OLD_MIN
NEW_MIN: MOV MIN, DI
OLD_MIN: INC DI
DEC CX
CMP CX, TMP
JNZ L2
SWAP: PUSH DI
MOV DI, MIN
MOV DL, BYTE PTR[BX+DI]
MOV DH, BYTE PTR[BX+SI]
MOV BYTE PTR [BX+SI], DL
MOV BYTE PTR [BX+DI], DH
POP DI
INC SI
MOV DI, SI
POP CX
LOOP L1
POP DX
POP DI
POP DI
RET
SORT ENDP
COMPARE_MIN PROC; (AX - A, CX - B CX - MIN)
PUSH AX
CMP AX, CX
JB B__A
JA A__B
A__B: MOV CX, CX
JMP EX
B__A: MOV CX, AX
JMP EX
EX: POP AX
RET
COMPARE_MIN ENDP
CSEG ENDS
END
OUTPUT.ASM
CSEG SEGMENT 'CODE'
ASSUME CS:CSEG
PUBLIC OUTPUT
OUTPUT PROC ; (BX - ARRAY ADDRESS, CX - ARRAY LENGTH)
PUSH DX
PUSH SI
PUSH AX
XOR SI, SI
MOV AH, 02H
OUTARR: MOV DL,[BX+SI]
INT 21H
INC SI
LOOP OUTARR
MOV DL, 10
INT 21H
POP AX
POP SI
POP DX
RET
OUTPUT ENDP
CSEG ENDS
END

Related

assembler x86 16bit - masm windows: running my program via the debugger (cv) bring different result that without debuging

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 want to make a bubble sort in assembly, and I don't understand why it's not working

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

Algorithm to assembly x86?

I have been for some days trying to translate an algorithm to assembly x86, and I did it. However I would like to print the final result that it is saved in "tmp", what instruction can I use? (I'm Spanish so I'm sorry if I say something wrong in English).
This is my algorithm:
tmp = NOT(L0)
tmp = tmp AND L1
tmp = NOT(NOT(tmp) OR NOT(L2))
tmp = NOT(tmp OR NOT(L3))
tmp = NOT(tmp + NOT(L4))
if (tmp == L5)
licence = correct
else
licence = incorrect
And this is it in assembly:
LicenceCorrect PROC
push ebp
mov ebp,esp
push ebx
push ecx
push edx
mov ebx, [ebp+8]
mov edx,[ebx]
mov ecx,edx
not ecx
mov edx,[ebx+4]
and ecx,edx
mov edx,[ebx+8]
not edx
not ecx
or ecx,edx
not ecx
mov edx,[ebx+16]
not edx
or ecx,edx
not ecx
;if
mov edx,[ebx]
cmp ecx,edx
jne cons
mov al,0
jmp next
cons:
mov al,1
next:
pop edx
pop ecx
pop ebx
pop ebp
ret
LicenceCorrect ENDP
END
Next code displays a number in AX (made with EMU8086). What MissPaper must do now is insert your procedure (LicenseCorrect) at the end of next code, and call it after "call dollars", then assign the value to AX (remove "12345").
Here it is for 32 bits:
.model small
.stack 100h
.data
buffer db 6 dup(?)
.code
start:
;INITIALIZE DATA SEGMENT.
mov ax, #data
mov ds, ax
;FIRST, FILL BUFFER WITH '$' (NECESSARY TO DISPLAY).
mov si, offset buffer
call dollars
;SECOND, CONVERT NUMBER TO STRING.
mov ax, 12345
mov si, offset buffer
call number2string
;THIRD, DISPLAY STRING.
mov dx, offset buffer
call printf
;FINISH PROGRAM.
mov ax, 4c00h
int 21h
;-----------------------------------------
;PARAMETER : DX POINTING TO '$' FINISHED STRING.
printf proc
mov ah, 9
int 21h
ret
printf endp
;------------------------------------------
;FILLS VARIABLE WITH '$'.
;USED BEFORE CONVERT NUMBERS TO STRING, BECAUSE
;THE STRING WILL BE DISPLAYED.
;PARAMETER : SI = POINTING TO STRING TO FILL.
dollars proc
mov cx, 6
six_dollars:
mov bl, '$'
mov [ si ], bl
inc si
loop six_dollars
ret
dollars endp
;------------------------------------------
;CONVERT A NUMBER IN STRING.
;ALGORITHM : EXTRACT DIGITS ONE BY ONE, STORE
;THEM IN STACK, THEN EXTRACT THEM IN REVERSE
;ORDER TO CONSTRUCT STRING (STR).
;PARAMETERS : AX = NUMBER TO CONVERT.
; SI = POINTING WHERE TO STORE STRING.
number2string proc
mov bx, 10 ;DIGITS ARE EXTRACTED DIVIDING BY 10.
mov cx, 0 ;COUNTER FOR EXTRACTED DIGITS.
cycle1:
mov dx, 0 ;NECESSARY TO DIVIDE BY BX.
div bx ;DX:AX / 10 = AX:QUOTIENT DX:REMAINDER.
push dx ;PRESERVE DIGIT EXTRACTED FOR LATER.
inc cx ;INCREASE COUNTER FOR EVERY DIGIT EXTRACTED.
cmp ax, 0 ;IF NUMBER IS
jne cycle1 ;NOT ZERO, LOOP.
;NOW RETRIEVE PUSHED DIGITS.
cycle2:
pop dx
add dl, 48 ;CONVERT DIGIT TO CHARACTER.
mov [ si ], dl
inc si
loop cycle2
ret
number2string endp
end start
Now the 64 bits version (for much bigger numbers in EAX), made with GUI Turbo Assembler x64 (http://sourceforge.net/projects/guitasm8086/):
.model small
.586
.stack 100h
.data
buffer db 11 dup(?)
.code
start:
;INITIALIZE DATA SEGMENT.
mov ax, #data
mov ds, ax
;FIRST, FILL BUFFER WITH '$' (NECESSARY TO DISPLAY).
mov esi, offset buffer
call dollars
;SECOND, CONVERT NUMBER TO STRING.
mov eax, 1234567890
mov esi, offset buffer
call number2string
;THIRD, DISPLAY STRING.
mov dx, offset buffer
call printf
;FINISH PROGRAM.
mov ax, 4c00h
int 21h
;-----------------------------------------
;PARAMETER : DX POINTING TO '$' FINISHED STRING.
printf proc
mov ah, 9
int 21h
ret
printf endp
;------------------------------------------
;FILLS VARIABLE WITH '$'.
;USED BEFORE CONVERT NUMBERS TO STRING, BECAUSE
;THE STRING WILL BE DISPLAYED.
;PARAMETER : ESI = POINTING TO STRING TO FILL.
dollars proc
mov cx, 11
six_dollars:
mov bl, '$'
mov [ esi ], bl
inc esi
loop six_dollars
ret
dollars endp
;------------------------------------------
;CONVERT A NUMBER IN STRING.
;ALGORITHM : EXTRACT DIGITS ONE BY ONE, STORE
;THEM IN STACK, THEN EXTRACT THEM IN REVERSE
;ORDER TO CONSTRUCT STRING (STR).
;PARAMETERS : EAX = NUMBER TO CONVERT.
; ESI = POINTING WHERE TO STORE STRING.
number2string proc
mov ebx, 10 ;DIGITS ARE EXTRACTED DIVIDING BY 10.
mov cx, 0 ;COUNTER FOR EXTRACTED DIGITS.
cycle1:
mov edx, 0 ;NECESSARY TO DIVIDE BY EBX.
div ebx ;EDX:EAX / 10 = EAX:QUOTIENT EDX:REMAINDER.
push dx ;PRESERVE DIGIT EXTRACTED (DL) FOR LATER.
inc cx ;INCREASE COUNTER FOR EVERY DIGIT EXTRACTED.
cmp eax, 0 ;IF NUMBER IS
jne cycle1 ;NOT ZERO, LOOP.
;NOW RETRIEVE PUSHED DIGITS.
cycle2:
pop dx
add dl, 48 ;CONVERT DIGIT TO CHARACTER.
mov [ esi ], dl
inc esi
loop cycle2
ret
number2string endp
end start
I didn't add your procedure because it uses the stack and I don't know what values to push before calling it.

Assembly Procedures not running Intel 8086

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.

a program works in Turbo Debugger when I step through it, but when I run it in TD or DOS it stops and Ctrl+Alt+Delete becomes the only option

The program was meant to display char table using BIOS int 10h, and it does it but only when I step through it in td. I thought that maybe while in debugger uninitialized registers contain zero, but while running they can possibly contain trash, therefore I put mov ax, 0003h instead of mov al, 3 and added xor dx, dx; but it does not works either.
.model tiny
.code
org 100h
start:
mov ax, 0003h
int 10h
xor dx, dx
mov si, 256
mov ax, 0900h
mov cx, 1
xor bh, bh
mov bl, 00011111b
cloop:
int 10h
push ax
mov ah, 2
inc dl
int 10h
mov ax, 0920h
int 10h
mov ah, 2
inc dl
int 10h
pop ax
inc al
test al, 0Fh
jnz con_loop
mov ah, 2
inc dh
xor dl, dl
int 10h
pop ax
con_loop:
dec si
jnz cloop
ret
end start
You need an additional PUSH. You should never trust BIOS/DOS/others to preserve AX even if it is not an output register.
test al,0Fh
jnz con_loop
push ax ;You forgot this!!!
mov ah,2
inc dh
xor dl,dl
int 10h
pop ax
con_loop:
You've got a pop instruction that doesn't correspond to a push:
push ax
...
pop ax
inc al
...
int 10h
pop ax <-- HERE
con_loop:
That last pop should be removed.

Resources