como crear una calculadora en assembler
STACK SEGMENT PARA STACK
DB64 DUP ('MYSTACK')
STACK ENDS
MYDATA SEGMENT PARA 'DATA'
BACK DB 2000 DUP (' ')
PANTALLA DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 25 DUP (' '), ' ------------------------------------- ', 25 DUP (' ')
DB 25 DUP (' '), ' | | ', 25 DUP (' ')
DB 25 DUP (' '), ' ------------------------------------- ', 25 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 25 DUP (' '), ' | 7 | 8 9 + ', 25 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' 4 5 6 - ', 25 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' 1 2 3 * ', 25 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' 0 / ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' HECHO ', 20 DUP (' ')
DB 20 DUP (' '), ' LUIS FERNANDO ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
TABLE DW 1234H, 5678H, 9ABCH, 0DEF0H,1111H, 2222H, 3333H, 4444H,5555H, 6666H, 7777H,8888H, 9999H,
0000H, 0AAAAH, 0BBBBH, 0CCCH, 0DDDDH, 0EEEEH, 0FFFFH
LSBANS DW ?
MYBANS DW ?
ERRORCAP DB 0
CANTIDAD DB 0
CANTUNOR DW 0
CANTDOSR DW 0
CANTUNON DB 6 , 0, 6 DUP (?)
CANTDOSN DB 6 , 0, 6 DUP (?)
FUNCION DB 0
RESULTA DB 13, 10, 13, 10, "EL RESULTADO ES: $"
RESULTAR DB 11 DUP (?)
MEN DB "PROGRAMA CALCULADORA, QUE LE PERMITE REALIZAR LAS"
DB 13, 10
DB "OPERACIONES DE SUMA, REST, MULTIPLICACION"
DB 13, 10, "Y DIVISION SOBRE DOS CANTIDADES ENTERA "
DB 13, 10, 13, 10, ¨$¨
MENU DB 13,1,13,10,¨DIGITE:,13,10,13,10
DB " (+) PARA SUMAR", 13,10
DB " (-) PARA RESTAR", 13,10
DB " (*) PARA MULTIPLICAR", 13,10
DB " (/) PARA DIVIDIR", 13,10
DB " (T) PARA TERMINAR", 13,10
ERROR DB 7, 7, 7, 13, 10, "ERROR:EN LA SELECCION DE LAS OPCIONES. $"
; DB 13, 10,13,10, "$"
ERROR1 DB 7, 7, 7, 13, 10,"$"
CANTUNOM DB 7, 7, 7, 13, 10,"PRIMER CANTIDAD: $"
CANTDOSM DB 7, 7, 7, 13, 10,"SEGUNDO CANTIDAD: $"
POTENCIA DW 0001H, 000AH, 0064H, 03E8H, 2710H
POTENCIAF DW $
MYDATA ENDS
MYCODE SEGMENTE PARA 'CODE' ; DEFINE EL SEG. CODITO PARA MASM
MYPROC PROC FAR ; EL PROCEDIMIENTO SE LLAMA MYPROC
ASSUME CS:MYCODE, DS:MYDATA, SS:STACK
PUSH DS ; GUARDA POSICION DE REG1 DS
SUB AX, AX ; PONE A AX A CERO
PUSH AX ; GUARDA CERO EN PILA, TAMBIEN
MOV AX, MYDATA ; PONE POSICION DE DATO EN AX
MOV DS, AX ;LO PONE EN REGISTRO DS
START: MOV AH, OFH
INT 10H
MOV AH, SEGD
MOV DS, AX
MOV DX, OFFSET MEN
CALL IMPRIME
MOV SI, OFFSET RESULTAR
ADD SI, 11
MOV AL, "$"
MOV [SI], AL
OTRA: MOV DX, OFFSET MENU
CALL IMPRIME
CALL OBTENTECLA
CMP AL, 49
JAE SIGUE
MOV DX, OFFSET ERROR
CALL IMPRIME
JMP OTRA
SIGUE: CMP AL, 53
JBE TODOBIEN
MOV DX, OFFSET ERROR
CALL IMPRIME
JMP OTRA
SUMA PROC NEAR
XOR DX, DX
MOV AX, CANTUNOR
MOV BX, CANTDOSR
ADD AX, BX
JNC SUMACOV
ADC DX, 0
SUMACONV: CALL CONVASCII
MOV DX, OFFSET RESULTA
CALL IMPRIME
MOV DX, OFFSET REULTAR
CALL IMPRIME
RET
SUMA ENDP
RESTA PROC NEAR
XOR DX, DX
MOV AX, CANTUNOR
MOV BX, CANTDOSR
SUB AX, BX
JNC RESTACONV
SBB DX, O
RESTACONV: CALL CONVASCII
MOV DX, OFFSET RESULTAR
CALL IMPRIME
RET
RESTA ENDP
MULTIPLICA PROC NEAR
XOR DX, DX
MOV AX, CANTUNOR
MOV BX, CANTDOSR
MUL BX
CALL CONVASCII
MOV DX, OFFSET RESULTA
CALL IMPRIME
MOV DX, OFFSET RESULTAR
CALL IMPRIME
RET
MULTIPLICA ENDP
DIVIDE PROC NEAR
MOV AX, CANTUNOR
MOV BX, CANTDOSR
CMP BX, 0
JNZ DIVIDE01
MOV CANTIDAD, 3
CALL HUBOERROR
RET
DIVIDE01: DIV BX
XOR DX, DX
CALL CONVASCII
MOV DX, OFFSET RESULTA
CALL IMPRIME
MOV DX, OFSSET RESULTAR
CALL IMPRIME
RET
DIVIDE ENDP
IMPRIME PROC NEAR
MOV AH, 9
INT 21H
RET
IMPRIME ENDP
OBTENTECLA PROC NEAR
MOV AH, 0
INT 16H
RET
OBTENTECLA ENDP
CONVNUM PROC NEAR
MOV DX, 0AH
CMP CANTIDA, 0
JNZ CONVNUM01
MOV DI, OFFSET CANTUNON + 1
MOV CX, [DI]
MOV SI, OFFSET CANTUNON + 2
JMP CONVNUM02
CONVNUM01: MOV DI, OFFSET CANTDOSN + 1
MOV CX, [DI]
MOV SI, OFFSET CANTDOSN + 2
CONVNUM02: XOR CH, CH
MOV DI, OFFSET POTENCIA
DEC SI
ADD SI, CX
XOR BX, BX
STD
CONVNUM03: LODSB
CMP AL, "0"
JB CONVNUM04
CMP AL, "9"
JA CONVNUM04
SUB AL, 30H
CBW
MOV DX, [DI]
MUL DX
JC CONVNUM05
ADD DI, 2
LOOP CONVNUM03
JMP CONVNUM06
CONVNUM04: CALL ERROR
JMP CONVNUM06
CONVNUM05: MOV CANTIDAD, 2
CALL ERROR
CONVNUM06: CLD
RET
CONVNUM ENDP
CONVASCII PRO NEAR
PUSH DX
PUSH AX
MOV SI, OFFSET RESULTAR
MOV CX, 10
MOV AL, "."
CONVASCII001 MOV [SI], AL
INC SI
LOOP CONVASCII01
POP AX
POP DX
MOV BX, AX
MOV AX, DX
MOV SI, OFFSSET RESULTAR
ADD SI, 11
MOV CX, 10
OBTENDIGITO: DEC SI
XOR DX, DX
DIV CX
MOV DI, AX
MOV AX, BX
DIV CX
MOV BX, AX
MOV AX, DI
ADD D1, 30H
MOV [SI], D1
OR AX, AX
JNZ OBTENDIGITO
OR BX, BX
JNZ OBTENDIGITO
RET
CONVASCII ENDP
;IMPRIME BLOCK
LEA BP, BACK
MOV DI, 09
MOV AH, 19
MOV AL, 1
MOV BL, 010011110B
MOV CX, 2000
INT IOH
;IMPRIME PANTALLA
LEA BP, PANTALLA
MOV DH, 09
MOV AH, 19
MOV AL, 1
MOV BL, 0101110B
MOV CX, 230H
INT 10H
RET
MYPROC ENDP
MYCODE ENDS
END
SI ALGUIEN ME PUEDE AYUDAR GRACIAS
DB64 DUP ('MYSTACK')
STACK ENDS
MYDATA SEGMENT PARA 'DATA'
BACK DB 2000 DUP (' ')
PANTALLA DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 25 DUP (' '), ' ------------------------------------- ', 25 DUP (' ')
DB 25 DUP (' '), ' | | ', 25 DUP (' ')
DB 25 DUP (' '), ' ------------------------------------- ', 25 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 25 DUP (' '), ' | 7 | 8 9 + ', 25 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' 4 5 6 - ', 25 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' 1 2 3 * ', 25 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' 0 / ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
DB 20 DUP (' '), ' HECHO ', 20 DUP (' ')
DB 20 DUP (' '), ' LUIS FERNANDO ', 20 DUP (' ')
DB 20 DUP (' '), ' ', 20 DUP (' ')
TABLE DW 1234H, 5678H, 9ABCH, 0DEF0H,1111H, 2222H, 3333H, 4444H,5555H, 6666H, 7777H,8888H, 9999H,
0000H, 0AAAAH, 0BBBBH, 0CCCH, 0DDDDH, 0EEEEH, 0FFFFH
LSBANS DW ?
MYBANS DW ?
ERRORCAP DB 0
CANTIDAD DB 0
CANTUNOR DW 0
CANTDOSR DW 0
CANTUNON DB 6 , 0, 6 DUP (?)
CANTDOSN DB 6 , 0, 6 DUP (?)
FUNCION DB 0
RESULTA DB 13, 10, 13, 10, "EL RESULTADO ES: $"
RESULTAR DB 11 DUP (?)
MEN DB "PROGRAMA CALCULADORA, QUE LE PERMITE REALIZAR LAS"
DB 13, 10
DB "OPERACIONES DE SUMA, REST, MULTIPLICACION"
DB 13, 10, "Y DIVISION SOBRE DOS CANTIDADES ENTERA "
DB 13, 10, 13, 10, ¨$¨
MENU DB 13,1,13,10,¨DIGITE:,13,10,13,10
DB " (+) PARA SUMAR", 13,10
DB " (-) PARA RESTAR", 13,10
DB " (*) PARA MULTIPLICAR", 13,10
DB " (/) PARA DIVIDIR", 13,10
DB " (T) PARA TERMINAR", 13,10
ERROR DB 7, 7, 7, 13, 10, "ERROR:EN LA SELECCION DE LAS OPCIONES. $"
; DB 13, 10,13,10, "$"
ERROR1 DB 7, 7, 7, 13, 10,"$"
CANTUNOM DB 7, 7, 7, 13, 10,"PRIMER CANTIDAD: $"
CANTDOSM DB 7, 7, 7, 13, 10,"SEGUNDO CANTIDAD: $"
POTENCIA DW 0001H, 000AH, 0064H, 03E8H, 2710H
POTENCIAF DW $
MYDATA ENDS
MYCODE SEGMENTE PARA 'CODE' ; DEFINE EL SEG. CODITO PARA MASM
MYPROC PROC FAR ; EL PROCEDIMIENTO SE LLAMA MYPROC
ASSUME CS:MYCODE, DS:MYDATA, SS:STACK
PUSH DS ; GUARDA POSICION DE REG1 DS
SUB AX, AX ; PONE A AX A CERO
PUSH AX ; GUARDA CERO EN PILA, TAMBIEN
MOV AX, MYDATA ; PONE POSICION DE DATO EN AX
MOV DS, AX ;LO PONE EN REGISTRO DS
START: MOV AH, OFH
INT 10H
MOV AH, SEGD
MOV DS, AX
MOV DX, OFFSET MEN
CALL IMPRIME
MOV SI, OFFSET RESULTAR
ADD SI, 11
MOV AL, "$"
MOV [SI], AL
OTRA: MOV DX, OFFSET MENU
CALL IMPRIME
CALL OBTENTECLA
CMP AL, 49
JAE SIGUE
MOV DX, OFFSET ERROR
CALL IMPRIME
JMP OTRA
SIGUE: CMP AL, 53
JBE TODOBIEN
MOV DX, OFFSET ERROR
CALL IMPRIME
JMP OTRA
SUMA PROC NEAR
XOR DX, DX
MOV AX, CANTUNOR
MOV BX, CANTDOSR
ADD AX, BX
JNC SUMACOV
ADC DX, 0
SUMACONV: CALL CONVASCII
MOV DX, OFFSET RESULTA
CALL IMPRIME
MOV DX, OFFSET REULTAR
CALL IMPRIME
RET
SUMA ENDP
RESTA PROC NEAR
XOR DX, DX
MOV AX, CANTUNOR
MOV BX, CANTDOSR
SUB AX, BX
JNC RESTACONV
SBB DX, O
RESTACONV: CALL CONVASCII
MOV DX, OFFSET RESULTAR
CALL IMPRIME
RET
RESTA ENDP
MULTIPLICA PROC NEAR
XOR DX, DX
MOV AX, CANTUNOR
MOV BX, CANTDOSR
MUL BX
CALL CONVASCII
MOV DX, OFFSET RESULTA
CALL IMPRIME
MOV DX, OFFSET RESULTAR
CALL IMPRIME
RET
MULTIPLICA ENDP
DIVIDE PROC NEAR
MOV AX, CANTUNOR
MOV BX, CANTDOSR
CMP BX, 0
JNZ DIVIDE01
MOV CANTIDAD, 3
CALL HUBOERROR
RET
DIVIDE01: DIV BX
XOR DX, DX
CALL CONVASCII
MOV DX, OFFSET RESULTA
CALL IMPRIME
MOV DX, OFSSET RESULTAR
CALL IMPRIME
RET
DIVIDE ENDP
IMPRIME PROC NEAR
MOV AH, 9
INT 21H
RET
IMPRIME ENDP
OBTENTECLA PROC NEAR
MOV AH, 0
INT 16H
RET
OBTENTECLA ENDP
CONVNUM PROC NEAR
MOV DX, 0AH
CMP CANTIDA, 0
JNZ CONVNUM01
MOV DI, OFFSET CANTUNON + 1
MOV CX, [DI]
MOV SI, OFFSET CANTUNON + 2
JMP CONVNUM02
CONVNUM01: MOV DI, OFFSET CANTDOSN + 1
MOV CX, [DI]
MOV SI, OFFSET CANTDOSN + 2
CONVNUM02: XOR CH, CH
MOV DI, OFFSET POTENCIA
DEC SI
ADD SI, CX
XOR BX, BX
STD
CONVNUM03: LODSB
CMP AL, "0"
JB CONVNUM04
CMP AL, "9"
JA CONVNUM04
SUB AL, 30H
CBW
MOV DX, [DI]
MUL DX
JC CONVNUM05
ADD DI, 2
LOOP CONVNUM03
JMP CONVNUM06
CONVNUM04: CALL ERROR
JMP CONVNUM06
CONVNUM05: MOV CANTIDAD, 2
CALL ERROR
CONVNUM06: CLD
RET
CONVNUM ENDP
CONVASCII PRO NEAR
PUSH DX
PUSH AX
MOV SI, OFFSET RESULTAR
MOV CX, 10
MOV AL, "."
CONVASCII001 MOV [SI], AL
INC SI
LOOP CONVASCII01
POP AX
POP DX
MOV BX, AX
MOV AX, DX
MOV SI, OFFSSET RESULTAR
ADD SI, 11
MOV CX, 10
OBTENDIGITO: DEC SI
XOR DX, DX
DIV CX
MOV DI, AX
MOV AX, BX
DIV CX
MOV BX, AX
MOV AX, DI
ADD D1, 30H
MOV [SI], D1
OR AX, AX
JNZ OBTENDIGITO
OR BX, BX
JNZ OBTENDIGITO
RET
CONVASCII ENDP
;IMPRIME BLOCK
LEA BP, BACK
MOV DI, 09
MOV AH, 19
MOV AL, 1
MOV BL, 010011110B
MOV CX, 2000
INT IOH
;IMPRIME PANTALLA
LEA BP, PANTALLA
MOV DH, 09
MOV AH, 19
MOV AL, 1
MOV BL, 0101110B
MOV CX, 230H
INT 10H
RET
MYPROC ENDP
MYCODE ENDS
END
SI ALGUIEN ME PUEDE AYUDAR GRACIAS
Tal vez te sirva este...
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
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
