Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ; factorial.asm
- ; this example gets the number from the user,
- ; and calculates factorial for it.
- ; supported input from 0 to 8 inclusive!
- ; this macro prints a char in AL and advances
- ; the current cursor position:
- .model small
- .stack 100h
- .data
- result dw ?
- ten dw 10
- msg1 db 0Dh,0Ah, 'enter the number: $'
- msg2 db 0Dh,0Ah, 'factorial: $'
- msg3 db 0Dh,0Ah, 'the result is too big!', 0Dh,0Ah, 'use values from 0 to 8.$'
- .code
- start:
- putc macro char
- push ax
- mov al, char
- mov ah, 0eh
- int 10h
- pop ax
- endm
- mov ax,@data
- mov ds,ax
- lea dx, msg1
- mov ah, 9
- int 21h
- jmp n1
- n1:
- call scan_num
- ; factorial of 0 = 1:
- mov ax, 1
- cmp cx, 0
- je print_result
- ; move the number to bx:
- ; cx will be a counter:
- mov bx, cx
- mov ax, 1
- mov bx, 1
- calc_it:
- mul bx
- cmp dx, 0
- jne overflow
- inc bx
- loop calc_it
- mov result, ax
- print_result:
- ; print result in ax:
- lea dx, msg2
- mov ah, 9
- int 21h
- jmp n2
- n2:
- mov ax, result
- call print_num_uns
- jmp exit
- overflow:
- lea dx, msg3
- mov ah, 9
- int 21h
- jmp n3
- n3:
- jmp start
- exit:
- ; wait for any key press:
- mov ah, 0
- int 16h
- mov ah,4ch
- int 21h
- ret
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; 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, 0Dh ; 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
- end
Add Comment
Please, Sign In to add comment