name "calc2" ; command prompt based simple calculator (+,-,*,/) for 8086. ; example of calculation: ; input 1 <- number: 10 ; input 2 <- operator: - ; input 3 <- number: 5 ; ------------------- ; 10 - 5 = 5 ; output -> number: 5 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; this maro is copied from emu8086.inc ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 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 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; org 100h jmp start ; define variables: msg0 db "note: calculator works with integer values only.",0Dh,0Ah db "to learn how to output the result of a float division see float.asm in examples",0Dh,0Ah,'$' msg1 db 0Dh,0Ah, 0Dh,0Ah, 'enter first number: $' msg2 db "enter the operator: + - * / : $" msg3 db "enter second number: $" msg4 db 0dh,0ah , 'the approximate result of my calculations is : $' msg5 db 0dh,0ah ,'thank you for using the calculator! press any key... ', 0Dh,0Ah, '$' err1 db "wrong operator!", 0Dh,0Ah , '$' smth db " and something.... $" ; operator can be: '+','-','*','/' or 'q' to exit in the middle. opr db '?' ; first and second number: num1 dw ? num2 dw ? start: mov dx, offset msg0 mov ah, 9 int 21h lea dx, msg1 mov ah, 09h ; output string at ds:dx int 21h ; get the multi-digit signed number ; from the keyboard, and store ; the result in cx register: call scan_num ; store first number: mov num1, cx ; new line: putc 0Dh putc 0Ah lea dx, msg2 mov ah, 09h ; output string at ds:dx int 21h ; get operator: mov ah, 1 ; single char input to AL. int 21h mov opr, al ; new line: putc 0Dh putc 0Ah cmp opr, 'q' ; q - exit in the middle. je exit cmp opr, '*' jb wrong_opr cmp opr, '/' ja wrong_opr ; output of a string at ds:dx lea dx, msg3 mov ah, 09h int 21h ; get the multi-digit signed number ; from the keyboard, and store ; the result in cx register: call scan_num ; store second number: mov num2, cx lea dx, msg4 mov ah, 09h ; output string at ds:dx int 21h ; calculate: cmp opr, '+' je do_plus cmp opr, '-' je do_minus cmp opr, '*' je do_mult cmp opr, '/' je do_div ; none of the above.... wrong_opr: lea dx, err1 mov ah, 09h ; output string at ds:dx int 21h exit: ; output of a string at ds:dx lea dx, msg5 mov ah, 09h int 21h ; wait for any key... mov ah, 0 int 16h ret ; return back to os. do_plus: mov ax, num1 add ax, num2 call print_num ; print ax value. jmp exit do_minus: mov ax, num1 sub ax, num2 call print_num ; print ax value. jmp exit do_mult: mov ax, num1 imul num2 ; (dx ax) = ax * num2. call print_num ; print ax value. ; dx is ignored (calc works with tiny numbers only). jmp exit do_div: ; dx is ignored (calc works with tiny integer numbers only). mov dx, 0 mov ax, num1 idiv num2 ; ax = (dx ax) / num2. cmp dx, 0 jnz approx call print_num ; print ax value. jmp exit approx: call print_num ; print ax value. lea dx, smth mov ah, 09h ; output string at ds:dx int 21h jmp exit ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; 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 ten DW 10 ; used as multiplier/divider by SCAN_NUM & PRINT_NUM_UNS. GET_STRING PROC NEAR PUSH AX PUSH CX PUSH DI PUSH DX MOV CX, 0 ; char counter. CMP DX, 1 ; buffer too small? JBE empty_buffer ; DEC DX ; reserve space for last zero. ;============================ ; Eternal loop to get ; and processes key presses: wait_for_key: MOV AH, 0 ; get pressed key. INT 16h CMP AL, 0Dh ; 'RETURN' pressed? JZ exit_GET_STRING CMP AL, 8 ; 'BACKSPACE' pressed? JNE add_to_buffer JCXZ wait_for_key ; nothing to remove! DEC CX DEC DI PUTC 8 ; backspace. PUTC ' ' ; clear position. PUTC 8 ; backspace again. JMP wait_for_key add_to_buffer: CMP CX, DX ; buffer is full? JAE wait_for_key ; if so wait for 'BACKSPACE' or 'RETURN'... MOV [DI], AL INC DI INC CX ; print the key: MOV AH, 0Eh INT 10h JMP wait_for_key ;============================ exit_GET_STRING: ; terminate by null: MOV [DI], 0 empty_buffer: POP DX POP DI POP CX POP AX RET GET_STRING ENDP
Write, Run & Share Assembly code online using OneCompiler's Assembly online compiler for free. It's one of the robust, feature-rich online compilers for Assembly language. Getting started with the OneCompiler's Assembly compiler is simple and pretty fast. The editor shows sample boilerplate code when you choose language as Assembly
and start coding.
Assembly language(asm) is a low-level programming language, where the language instructions will be more similar to machine code instructions.
Every assembler may have it's own assembly language designed for a specific computers or an operating system.
Assembly language requires less execution time and memory. It is more helful for direct hardware manipulation, real-time critical applications. It is used in device drivers, low-level embedded systems etc.
Assembly language usually consists of three sections,
Data section
To initialize variables and constants, buffer size these values doesn't change at runtime.
bss section
To declare variables
text section
_start
specifies the starting of this section where the actually code is written.
There are various define directives to allocate space for variables for both initialized and uninitialized data.
variable-name define-directive initial-value
Define Directive | Description | Allocated Space |
---|---|---|
DB | Define Byte | 1 byte |
DW | Define Word | 2 bytes |
DD | Define Doubleword | 4 bytes |
DQ | Define Quadword | 8 bytes |
DT | Define Ten Bytes | 10 bytes |
Define Directive | Description |
---|---|
RESB | Reserve a Byte |
RESW | Reserve a Word |
RESD | Reserve a Doubleword |
RESQ | Reserve a Quadword |
REST | Reserve a Ten Bytes |
Constants can be defined using
CONSTANT_NAME EQU regular-exp or value
%assign constant_name value
%define constant_name value
Loops are used to iterate a set of statements for a specific number of times.
mov ECX,n
L1:
;<loop body>
loop L1
where n specifies the no of times loops should iterate.
Procedure is a sub-routine which contains set of statements. Usually procedures are written when multiple calls are required to same set of statements which increases re-usuability and modularity.
procedure_name:
;procedure body
ret