como crear una calculadora en assembler

luis
30 de Noviembre del 2005
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

Einstein
30 de Noviembre del 2005
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

Carmela
30 de Noviembre del 2005
Solo quiero saber si lo lograste siempre, de lo contrario creo que puedo ayudarte...pues me facilitaron unas páginas donde esta este programa..pero sólo cálcula valores enteros