Uno de los programas más sencillos, pero en cierta forma práctico, es uno que despliegue una cadena de caracteres en la pantalla. Eso es lo que hace el siguiente programa:
Programa :
; Primero definimos el modelo de memoria, en este caso small
.MODEL SMALL
.CODE ; Declaramos el área que contendrá
el código
Inicio: ; Etiqueta de inicio del programa:
MOV AX,@DATA ; Vamos a colocar la dirección
del segmento de datos
MOV DS,AX ; en DS, usando como intermediario a AX
MOV DX,OFFSET Cadena ; Colocamos en DX la dirección, dentro del
; segmento, de la cadena a desplegar
MOV AH,09 ; Utilizaremos la función 09 de la interrupción
INT 21H ; 21H para desplegar la cadena.
MOV AH,4CH ; Por medio de la función 4CH de la interrupción
INT 21H ; 21H terminaremos nuestro programa
.DATA ; Declaramos el semento de datos
Cadena DB 'Mensaje del programa.$' ; Cadena a desplegar
.STACK ; Declaramos la pila
END Inicio ; Final de nuestro programa
Ya se explicó en el tutorial un programa casi igual a este, por lo tanto no requiere ningún comentario adicional.
Cuando se crea un programa no es necesario escribir los comentarios que van despues de las comillas, sin embargo es una técnica recomendable para que en caso de errores o mejoras al código sea más sencillo encontrar la parte deseada.
Para ensamblar este programa primero se guarda en formato ASCII con un nombre válido, por ejemplo: program1.asm
Para ensamblarlo se utiliza el MASM, el comando de ensamble es: masm program1;
Para enlazarlo y hacerlo ejecutable tecleamos: link program1;
Una vez terminados estos pasos es posible ejecutarlo tecleando: program1 [Enter]
Para utilizar el programa directamente en su computadora guarde este archivo como ASCII o texto, llévelo a su PC, con algun editor elimine todos estos comentarios y los comentarios del principio y ensámblelo.
Desplegar números hexadecimales del 15 al 0
Este programa despliega los 16 caracteres correspondientes al código hexadecimal en orden descendente.
Programa:
; Inicio del programa, definimos el modelo de memoria a usar y el segmento
; de código
.MODEL SMALL ; Modelo de memoria
.CODE ; Area de código
Inicio: ; Etiqueta de inicio del programa
MOV AX,@DATA ; Inicializa el registro DS con la dirección dada
MOV DS,AX ; por @DATA (Segmento de datos).
MOV DX, OFFSET Titulo ; Obtiene la dirección de la cadena de caracteres
MOV AH,09 ; Usamos la función 09H de la interrupción 21H
INT 21H ; para desplegar la cadena cuya dirección obtuvimos.
MOV CX,16 ; Contador de caracteres que se mostrarán
MOV BX, OFFSET Cadena ; Permite acceso a la cadena donde se encuentran los
; valores a desplegar
Ciclo: ; Etiqueta para generar un ciclo
MOV AL,CL ; Coloca en AL el número a traducir y lo traduce
XLAT ; usando la instrucción XLAT
MOV DL,AL ; Coloca en DL el valor a ser desplegado por medio de la
MOV AH,02 ; función 2 de la interrupción 21H
INT 21H ; Despliega el caracter
MOV DL,10 ; Salta una linea desplegando el caracter 10
INT 21H ; Despliega el caracter
MOV DL,13 ; Produce un retorno de carro desplegando el caracter 13
INT 21H ; Despliega el retorno de carro
LOOP Ciclo ; Decrementa en uno a CX y brinca a la etiqueta Ciclo
; siempre y cuando CX no sea igual a cero
MOV AH,4C ; Utiliza la función 4C de la interrupción 21H para
INT 21H ; finalizar el programa
; Inicio del segmento de datos
.DATA ;Define el segmento de datos
Titulo DB 13,10,'Desplegar los números hexadecimales del 15 al 1'
DB 13,10,'$' ; Cadena a desplegar al inicio del programa
Cadena DB '0123456789ABCDEF' ; Cadena con los d'gitos hexadecimales
; Declaración del segmento de la pila
.STACK
END Inicio ;Declaración del final del programa
El comando XLAT busca la cadena o tabla localizada en BX, el registro AL contiene el número de bytes, a partir de la dirección de inicio, que se recorrerá el apuntador para buscar un dato, el contenido de AL es remplazado por el byte donde se encuentra el apuntador.
El proceso de ensamblado es igual al del ejemplo anterior.
Operaciones básicas
En el siguiente ejemplo se utilizan la mayor parte de las instrucciones vistas en el tutorial, su objetivo es realizar las operaciones de suma, resta, multiplicación o división de dos cantidades.
Para accesar a cada una de las opciones disponibles se hace uso de un menú en el que se presentan las operaciones disponibles.
Programa:
.MODEL SMALL ; Define el modelo de memoria
.DATA ; Define el segmentos de datos
ErrorCAP DB 0 ;Bandera de error en la captura de las cantidades
Cantidad DB 0 ;Cantidad sobre la que se opera. Si es 0 la cantidad
; será la 1, y si es 1 será la 2.
CantUnoR DW 0 ;Guardará la cantidad 1 convertida en binario
CantDosR DW 0 ;Guardará la cantidad 2 convertida en binario
CantUnoN DB 6,0,6 DUP(?) ;Variable que almacena la cantidad 1
CantDosN DB 6,0,6 DUP(?) ;Variable que almacena la cantidad 2
Funcion DB 0 ;Variable que almacena la opción a realizar
Resulta DB 13,10,'Resultado: $'
ResultaR DB 11 DUP(?)
Mensaje DB 13,10,'Operaciones básicas entre dos números'
DB 13,10,13,10,'$'
Pregunta DB 13,10,'Presione: ',13,10
DB ' 1 Multiplicación ',13,10
DB ' 2 División ',13,10
DB ' 3 Suma ',13,10
DB ' 4 Resta ',13,10
DB ' 5 Salir ',13,10,'$'
Error DB 7,13,10,'Selección inválida (1-5)',13,10,'$'
Error1 DB 7,13,10,'Cantidad 1 inválida. ',13,10,'$'
Error2 DB 7,13,10,'Cantidad 2 inválida. ',13,10,'$'
Error3 DB 7,13,10,'Cantidad fuera de rango (65535) ',13,10,'$'
Error4 DB 7,13,10,'Intento de división por cero. ',13,10,'$'
CantUnoM DB 13,10,'Introduzca la cantidad 1 (Menor a 65535): $'
CantDosM DB 13,10,'Introduzca la cantidad 2 (Menor a 65535): $'
; Tabla de potencias para conversión binaria/ASCII
Potencia DW 0001h, 000Ah, 0064h, 03E8h, 2710h
PotenciaF DW $
.CODE ;Define el área de código
Empieza: ;Etiqueta de inicio del programa
Mov AH, 0Fh ;Obtiene modo de video actual
Int 10h
Mov AH, 00 ;Cambia el modo de video al mismo anterior
Int 10h ; con la finalidad de que se borre la pantalla
Mov AX, @Data ;Obtiene la dirección del segmento de datos
Mov Ds, Ax ;Inicializa a DS con esa dirección
Mov Dx, Offset Mensaje ;Despliega el t'tulo del programa
Call Imprime ;Llama a un procedimiento
Mov Si, Offset ResultaR ;Inicializa la variable ResultaR
Add Si,11
Mov Al,'$'
Mov [Si], Al
OTRA:
Mov Dx,Offset Pregunta ;Despliega menú de opciones
Call Imprime
Call ObtenTecla ;Espera a que se presione la opción deseada
Cmp Al, 49 ;Compara la selección con el d'gito 1 ASCII
Jae SIGUE ;Si la opción es mayor a 1 brinca a SIGUE
Mov Dx, Offset Error ;Despliega mensaje de error
Call Imprime
Jmp OTRA ;Brinca a OTRA para volver a preguntar
SIGUE:
Cmp Al,53 ;Compara la selección con el d'gito 5 ASCII
Jbe TODOBIEN ;Si es menor a 5 brinca a TODOBIEN, sino continúa
Mov Dx, Offset Error ;Si la opción fué mayor a 5 despiega el error
Call Imprime
Jmp OTRA
TODOBIEN:
Cmp Al,53 ;Compara la seleción con el d'gito 5 ASCII
Jnz CHECATODO ;Si no es igual brinca a CHECATODO
Jmp FUNCION5 ;Si es igual brinca a FUNCION5 para terminar
CHECATODO:
Mov Funcion, Al ;Guarda el número de función a realizar
CAPCANT01:
Mov Dx, Offset CantUnoM ;Mensaje de captura de la cantidad 1
Call Imprime
Mov Ah, 0Ah ;Captura la cantidad (hasta 8 d'gitos)
Mov Dx, Offset CantUnoN
Int 21h
Mov ErrorCAP, 0 ;Supone que no hay errores y que se está
Mov Cantidad, 0 ; operando sobre la cantidad 1
Call ConvNUM ;Convierte cantidad 1 a binario
Cmp ErrorCAP, 1 ;Verifica si hubo error
Jz CAPCANT01 ;En caso afirmativo regresa a la captura.
Mov CantUnoR, Bx ;Guarda el resultado de la conversión
CAPCANT02:
Mov ErrorCAP, 0 ;Supone que no hay error
Mov Cantidad, 1 ;Indica a ConvNUM que se trabajará con cantidad 2
Mov Dx, Offset CantDosM ;Mensaje de captura de cantidad 2
Call Imprime
Mov Ah, 0Ah ;Captura de la cantidad 2
Mov Dx, Offset CantDosM
Int 21H
Call ConvNum ;Convierte la cantidad 2 a binario
Cmp ErrorCAP, 1 ;Verifica si existi— algun error
Jz, CAPCANT02 ;En caso afirmativo regresa a la captura
Mov CantDosR, Bx ;Almacena el valor binario de cantidad 2
;La siguiente parte es el proceso de selección de la operación
;Que se realizara:
Mov Al, Funcion ;Carga en Al la función que seleccion— el usuario
Cmp Al, 31h ;Revisa si es 1
Jne FUNCION2 ;Si no es brinca a FUNCION2
Call Multiplica ;Multiplica las cantidades
Jmp OTRA ;Regresa al menú principal
FUNCION2:
Cmp Al, 32h ;Revisa si es 2
Jne FUNCION3 ;Si no es brinca a FUNCION3
Call Divide ;Divide las cantidades
Jmp OTRA
FUNCION3:
Cmp Al, 33h ;Revisa si es 3
Jne FUNCION4 ;Si no es brinca a FUNCION4
Call Suma ;Suma las cantidades
Jmp OTRA
FUNCION4:
Cmp Al, 34h ;Revisa si es 4
Jne FUNCION5 ;Si no es brinca a FUNCION5
Call Resta ;Resta las cantidades
Jmp OTRA
FUNCION5:
Mov Ax, 4C00h ;Esta función termina la ejecución
Int 21h ;del programa
; Procedimientos o rutinas del programa
Multiplica Proc Near ;Indicador de inicio de procedimiento
Xor Dx, Dx ;Dx = 0
Mov Ax, CantUnoR ;Primera cantidad
Mov Bx, CantDosR ;Segunda cantidad
Mul Bx ;Multiplica
Call ConvASCII ;Convierte en ASCII
Mov Dx, Offset Resulta ;Imprime mensaje del resultado
Call Imprime
Mov Dx, Offset ResultaR ;Imprime resultado
Call Imprime
Ret ;Regresa al programa principal
Multiplica Endp ;Indicador de fin de procedimiento
Divide Proc Near
Mov Ax, CantUnoR ;Carga la cantidad 1 (dividendo)
Mov Bx, CantDosR ;Carga la cantidad 2 (divisor)
Cmp Bx, 0 ;Revisa que el divisor no sea cero
Jnz DIVIDE01 ;Si no es cero brinca a DIVIDE01
Mov Cantidad, 3 ;Hubo error asi que despliega el mensaje y regresa al
programa
Call HuboError
Ret
DIVIDE01:
Div Bx ;Efectúa la división
Xor Dx, Dx ;Dx = 0. El residuo no es utilizado
Call ConvASCII ;Convierte en ASCII el resultado
Mov Dx, Offset Resulta ;Despliega el mensaje del resultado
Call Imprime
Mov Dx, Offset ResultaR ;Depliega el resultado
Call Imprime
Ret
Divide Endp
Suma Proc Near
Xor Dx, Dx ;Dx = 0 por si acaso existe acarreo
Mov Ax, CantUnoR ;Cantidad 1
Mov Bx, CantDosR ;Cantidad 2
Add Ax, Bx ;Realiza la suma
Jnc SUMACONV ;Si no existi— acarreo brinca a SUMACONV
Adc Dx,0 ;Si existi—
SUMACONV:
Call ConvASCII ;Convierte en ASCII el resultado
Mov Dx, Offset Resulta ;Despliega el mensaje del resultado
Call Imprime
Mov Dx, Offset ResultaR ;Despliega el resultado
Call Imprime
Ret
Suma Endp
Resta Proc Near
Xor Dx, Dx ;Dx = 0 por si existe acarreo
Mov Ax, CantUnoR ;Ax = cantidad 1
Mov Bx, CantDosR ;Bx = cantidad 2
Sub Ax, Bx ;Realiza la resta
Jnc RESTACONV ;Si no hay acarreo brinca a RESTACONV
Sbb Dx,0 ;Si hay acarreo
RESTACONV:
Call ConvASCII ;Convierte en ASCII el resultado
Mov Dx, Offset Resulta ;Despliega el mensaje del resultado
Call Imprime
Mov Dx, Offset ResultaR ;Despliega el resultado
Call Imprime
Ret
Resta Endp
Imprime Proc Near
Mov Ah, 09 ;Utiliza la función 9 de la interrupción
Int 21h ;21h para desplegar una cadena
Ret
Imprime Endp
ObtenTecla Proc Near
Mov ah, 0 ;Utiliza la interrupción 16h para
Int 16h ; leer una tecla
Ret
ObtenTecla Endp
ConvNum Proc Near
Mov Dx, 0Ah ;Multiplicador es 10
Cmp Cantidad, 0 ;Verifica si es la cantidad 1
Jnz CONVNUM01 ;No fué, entonces es cantidad 2 y brinca
Mov Di, Offset CantUnoN + 1 ;Bytes leidos en la cantidad 1
Mov Cx, [Di]
Mov Si, Offset CantUnoN + 2 ;La cantidad 1
Jmp CONVNUM02
CONVNUM01:
Mov Di, Offset CantDosN + 1 ;Bytes leidos de la cantidad 2
Mov Cx, [Di]
Mov Si, Offset CantDosN + 2 ;La cantidad 2
CONVNUM02:
Xor Ch, Ch ;CH = 0
Mov Di, Offset Potencia ;Dirección de la tabla de potencias
Dec Si
Add Si, Cx
Xor Bx, Bx
Std
CONVNUM3:
Lodsb ;Carga en AL el byte cuya dirección es DS:SI
Cmp Al, 0
;Compara el byte con el
d'gito 0
Jb CONVNUM04 ;Si es menor es inválido y brinca
Cmp Al, 9
;Compara el byte con el
d'gito 9
Ja CONVNUM04 ;Si es mayor es inválido y brinca
Sub Al, 30h ;Convierte el d'gito de ASCII a binario
Cbw ;Convierte a palabra
Mov Dx, [Di] ;Obtiene la potencia a ser usada para multiplicar
Mul Dx ;Multiplica el número
Jc CONVNUM05 ;Si hay acarreo brinca (fué mayor a 65535)
Add Bx, Ax ;Suma el resultado a BX
Jc CONVNUM05 ;Si hay acarreo brinca
Add Di, 2 ;Va a la siguiente potencia de 10
Loop CONVNUM03 ;Brinca hasta que CX sea igual a 0
Jmp CONVNUM06
CONVNUM04:
Call HuboERROR ;Hubo algun error, depliega mensaje
Jmp CONVNUM06 ;Brinca a CONVNUM06
CONVNUM05:
Mov Cantidad, 2 ;Hubo acareo en la conversión, lo que
Call HuboERROR ; significa que la cantidad es mayor a 65535
CONVNUM06:
Cld ;Regresa la bandera de dirección a su estado
Ret ; normal
ConvNum Endp
ConvASCII Proc Near
Push Dx
Push Ax ;Guarda el resultado en la pila
Mov Si, Offset ResultaR ;Inicializa la variable ResultaR
Mov Cx, 10 ; llenandola con asteriscos
Mov Al, '*'
ConvASCII01:
Mov [Si], Al
Inc Si
Loop ConvASCII01
Pop Ax
Pop Bx
Mov Bx, Ax ;Palabra baja de la cantidad
Mov Ax, Dx ;Palabra alta de la cantidad
Mov Si, Offset ResultaR ;Cadena donde se guarda el resultado
Add Si, 11
Mov Cx, 10 ;Divisor = 10
OBTENDIGITO:
Dec Si
Xor Dx, Dx ;DX contrendrá el residuo
Div Cx ;Divide la palabra alta
Mov Di, Ax ;Guarda cociente en DI
Mov Ax, Bx ;Carga palabra baja en AX
Div Cx ;DX contiene registro de la división
Mov Bx, Ax ;Guarda el cociente
Mov Ax, Di ;Regresa la palabra alta
Add Dl, 30h ;Convierte residuo en ASCII
Mov [Si], Dl ;Lo almacena
Or Ax, Ax ;Si la palabra alta no es cero
Jnz OBTENDIGITO ; brinca a OBTENDIGITO
Or Bx, Bx ;Si la palabra baja no es cero
Jnz OBTENDIGITO ; brinca a OBTENDIGITO
Ret
ConvASCII Endp
HuboERROR Proc Near
Cmp Cantidad,0 ;Es la cantidad 1?
Jnz HUBOERROR02 ;no
Mov Dx, Offset Error1
Call Imprime
Mov ErrorCAP, 1 ;Enciende la bandera de error
Jmp HUBOERROR05
HUBOERROR02:
Cmp Cantidad, 1 ;Es la cantidad 2?
Jnz HUBOERROR03 ;no
Mov Dx, Offset Error2
Call Imprime
Mov ErrorCAP, 1
jmp HUBOERROR05
HUBOERROR03:
Cmp Cantidad, 2 ;Es una cantidad fuera de rango?
Jnz HUBOERROR04 ;no
Mov Dx, Offset Error3
Call Imprime
Mov ErrorCAP, 1
Jmp HUBOERROR05
HUBOERROR04:
Mov Dx, Offset Error4 ;Error de división por cero
Call Imprime
Mov ErrorCAP, 1
HUBOERROR05:
Ret
HuboERROR Endp
.STACK
End Empieza
Ing. M—nico Brise–o C.
Idea original
Hugo Eduardo Pérez P.
Desarrollo e implementación
Bibliograf'a
Lenguaje Ensamblador Para Microcomputadoras IBM
J. Terry Godfrey
Ed. Prentice Hall Hispanoamericana, S.A.
México
Ensamblador Básico
A. Rojas
Ed. Computec Editores S.A. de C.V.
México
IBM Personal Computer Assembly Languaje Tutorial
Joshua Auerbach
Yale University