; sort.asm
name "sort"
; simple sort
; this program inputs 3 numbers and
; sorts them from largest to smallest
; this macro prints a char in AL and advances
; the current cursor position:
putc macro char
push ax
mov al, char
mov ah, 0eh
int 10h
pop ax
endm
; this macro sets current cursor position:
gotoxy macro col, row
push ax
push bx
push dx
mov ah, 02h
mov dh, row
mov dl, col
mov bh, 0
int 10h
pop dx
pop bx
pop ax
endm
data segment
cr equ 0dh
lf equ 0ah
dollar equ '$'
new_line db lf, cr, dollar
msg1 db "enter first value (-32768..32767)!"
db lf, cr, dollar
msg2 db lf, cr, "enter second value (-32768..32767)!"
db lf, cr, dollar
msg3 db lf, cr, "enter third value (-32768..32767)!"
db lf, cr, dollar
msg4 db cr, lf, cr, lf, "after sorting from biggest to smallest:", dollar
msg5 db cr, lf, "num1 = ", dollar
msg6 db cr, lf, "num2 = ", dollar
msg7 db cr, lf, "num3 = ", dollar
num1 dw ?
num2 dw ?
num3 dw ?
ends
stack segment
dw 100h dup(?)
ends
code segment
start proc far
; prepare for return to os:
push ds
mov ax, 0
push ax
; set segment registers:
mov ax, data
mov ds, ax
mov es, ax
; clear the screen:
call clear_screen
; position the cursor at row=3 and column=0
gotoxy 0, 3
; ask for first number:
lea dx, msg1
call puts ; display the message.
call scan_num ; input the number into cx.
mov num1, cx
; ask for second number:
lea dx, msg2
call puts ; display the message.
call scan_num ; input the number into cx.
mov num2, cx
; ask for third number:
lea dx, msg3
call puts ; display the message.
call scan_num ; input the number into cx.
mov num3, cx
; sorting:
mov bx, num1
mov cx, num2
call sort ; exchange if bx<cx
mov num1, bx
mov num2, cx
mov bx, num2
mov cx, num3
call sort ; exchange if bx<cx
mov num2, bx
mov num3, cx
mov bx, num1
mov cx, num2
call sort ; exchange if bx<cx
mov num1, bx
mov num2, cx
; print the result:
lea dx, msg4
call puts
lea dx, msg5
call puts
mov ax, num1
call print_num ; print ax.
lea dx, msg6
call puts
mov ax, num2
call print_num ; print ax.
lea dx, msg7
call puts
mov ax, num3
call print_num ; print ax.
lea dx, new_line
call puts
mov ah, 0
int 16h
retf
start endp
;***********************************
; displays the message (dx-address),
; uses dos function to print:
puts proc near
push ax
mov ah, 09h
int 21h
pop ax
ret
endp
;************************************
; if bx < cx then exchanges them
; (works with signed numbers)
sort proc near
cmp bx, cx
jge compared
xchg bx, cx
compared:
ret
endp
;************************************
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; these functions are copied from emu8086.inc ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; gets the multi-digit SIGNED number from the keyboard,
; and stores the result in CX register:
SCAN_NUM PROC NEAR
PUSH DX
PUSH AX
PUSH SI
MOV CX, 0
; reset flag:
MOV CS:make_minus, 0
next_digit:
; get char from keyboard
; into AL:
MOV AH, 00h
INT 16h
; and print it:
MOV AH, 0Eh
INT 10h
; check for MINUS:
CMP AL, '-'
JE set_minus
; check for ENTER key:
CMP AL, 13 ; carriage return?
JNE not_cr
JMP stop_input
not_cr:
CMP AL, 8 ; 'BACKSPACE' pressed?
JNE backspace_checked
MOV DX, 0 ; remove last digit by
MOV AX, CX ; division:
DIV CS:ten ; AX = DX:AX / 10 (DX-rem).
MOV CX, AX
PUTC ' ' ; clear position.
PUTC 8 ; backspace again.
JMP next_digit
backspace_checked:
; allow only digits:
CMP AL, '0'
JAE ok_AE_0
JMP remove_not_digit
ok_AE_0:
CMP AL, '9'
JBE ok_digit
remove_not_digit:
PUTC 8 ; backspace.
PUTC ' ' ; clear last entered not digit.
PUTC 8 ; backspace again.
JMP next_digit ; wait for next input.
ok_digit:
; multiply CX by 10 (first time the result is zero)
PUSH AX
MOV AX, CX
MUL CS:ten ; DX:AX = AX*10
MOV CX, AX
POP AX
; check if the number is too big
; (result should be 16 bits)
CMP DX, 0
JNE too_big
; convert from ASCII code:
SUB AL, 30h
; add AL to CX:
MOV AH, 0
MOV DX, CX ; backup, in case the result will be too big.
ADD CX, AX
JC too_big2 ; jump if the number is too big.
JMP next_digit
set_minus:
MOV CS:make_minus, 1
JMP next_digit
too_big2:
MOV CX, DX ; restore the backuped value before add.
MOV DX, 0 ; DX was zero before backup!
too_big:
MOV AX, CX
DIV CS:ten ; reverse last DX:AX = AX*10, make AX = DX:AX / 10
MOV CX, AX
PUTC 8 ; backspace.
PUTC ' ' ; clear last entered digit.
PUTC 8 ; backspace again.
JMP next_digit ; wait for Enter/Backspace.
stop_input:
; check flag:
CMP CS:make_minus, 0
JE not_minus
NEG CX
not_minus:
POP SI
POP AX
POP DX
RET
make_minus DB ? ; used as a flag.
SCAN_NUM ENDP
; this procedure prints number in AX,
; used with PRINT_NUM_UNS to print signed numbers:
PRINT_NUM PROC NEAR
PUSH DX
PUSH AX
CMP AX, 0
JNZ not_zero
PUTC '0'
JMP printed
not_zero:
; the check SIGN of AX,
; make absolute if it's negative:
CMP AX, 0
JNS positive
NEG AX
PUTC '-'
positive:
CALL PRINT_NUM_UNS
printed:
POP AX
POP DX
RET
PRINT_NUM ENDP
; this procedure prints out an unsigned
; number in AX (not just a single digit)
; allowed values are from 0 to 65535 (FFFF)
PRINT_NUM_UNS PROC NEAR
PUSH AX
PUSH BX
PUSH CX
PUSH DX
; flag to prevent printing zeros before number:
MOV CX, 1
; (result of "/ 10000" is always less or equal to 9).
MOV BX, 10000 ; 2710h - divider.
; AX is zero?
CMP AX, 0
JZ print_zero
begin_print:
; check divider (if zero go to end_print):
CMP BX,0
JZ end_print
; avoid printing zeros before number:
CMP CX, 0
JE calc
; if AX<BX then result of DIV will be zero:
CMP AX, BX
JB skip
calc:
MOV CX, 0 ; set flag.
MOV DX, 0
DIV BX ; AX = DX:AX / BX (DX=remainder).
; print last digit
; AH is always ZERO, so it's ignored
ADD AL, 30h ; convert to ASCII code.
PUTC AL
MOV AX, DX ; get remainder from last div.
skip:
; calculate BX=BX/10
PUSH AX
MOV DX, 0
MOV AX, BX
DIV CS:ten ; AX = DX:AX / 10 (DX=remainder).
MOV BX, AX
POP AX
JMP begin_print
print_zero:
PUTC '0'
end_print:
POP DX
POP CX
POP BX
POP AX
RET
PRINT_NUM_UNS ENDP
ten DW 10 ; used as multiplier/divider by SCAN_NUM & PRINT_NUM_UNS.
; this procedure clears the screen,
; (done by scrolling entire screen window),
; and sets cursor position on top of it:
CLEAR_SCREEN PROC NEAR
PUSH AX ; store registers...
PUSH DS ;
PUSH BX ;
PUSH CX ;
PUSH DI ;
MOV AX, 40h
MOV DS, AX ; for getting screen parameters.
MOV AH, 06h ; scroll up function id.
MOV AL, 0 ; scroll all lines!
MOV BH, 07 ; attribute for new lines.
MOV CH, 0 ; upper row.
MOV CL, 0 ; upper col.
MOV DI, 84h ; rows on screen -1,
MOV DH, [DI] ; lower row (byte).
MOV DI, 4Ah ; columns on screen,
MOV DL, [DI]
DEC DL ; lower col.
INT 10h
; set cursor position to top
; of the screen:
MOV BH, 0 ; current page.
MOV DL, 0 ; col.
MOV DH, 0 ; row.
MOV AH, 02
INT 10h
POP DI ; re-store registers...
POP CX ;
POP BX ;
POP DS ;
POP AX ;
RET
CLEAR_SCREEN ENDP
code ends
end start ; stop assembler and set entry point.
; - Other Assembler Source Codes -
; - asm2html by emu8086 -