jueves, 7 de marzo de 2019

JMP EMU8086

Vamos a hablar de la librería JMP. Y estos son algunos de los ejemplos de los saltos:


Y aquí el primer ejemplo de la librería JMP:


org    100h

mov    ax, 5          ; set ax to 5.
mov    bx, 2          ; set bx to 2.

jmp    calc            ; go to 'calc'.

back:  jmp stop      ; go to 'stop'.

calc:
add    ax, bx         ; add bx to ax.
jmp    back           ; go 'back'.

stop:

ret                   ; return to operating system.




Y el segundo ejemplo de saltos es el que viene con un IF:

include 'emu8086.inc'
.model small
.stack
.data
 
    num1 db 8
    num2 db 8

.code
    main:
    mov ax, @data
    mov ds, ax
    
    mov al, num1
    
    cmp al, num2
    
    jc mayor2
    jz igual
    jnz mayor1
    
.exit

igual:
    printn 'LOS NUMEROS SON IGUALES'
    jmp fin


mayor1:
    printn 'EL PRIMER NUMERO ES MAYOR'
    jmp fin

mayor2:
    print 'EL SEGUNDO NUMERO ES MAYOR'
    jmp fin     

fin:

.exit





miércoles, 6 de marzo de 2019

BANDERAS

CODIGO
.model small
.stack
.data

.code
     mov al,255
     mov bl,1
     add al,bl


.exit
end 




.model small
.stack
.data

.code
     mov al,2
     mov bl,2
     sub al,bl


.exit

end




1.8 DESPLEGADO DE MENSAJES DE MONITOR

Usando el servicio 02 de 21h:

El servicio 02 de la interrupción 21h nos permitirá mostrar en pantalla el despliegue de un carácter en pantalla, generalmente un carácter guardado en alguna de las localidades de dx:



Usando el servicio 09 de 21h:

El servicio  09 de esta interrupción nos pemitira imprimir cadenas de caracteres. Esto se puede hacer de 2 maneras, utilizando offset o con el nmonico lea.

Offset: En ingeniería informática y programación de bajo nivel (como el lenguaje ensamblador), un offset normalmente indica el número de posiciones de memoria sumadas a una dirección base para conseguir una dirección absoluta específica. Con este significado (que es el original) de offset, sólo se usa la unidad básica de direccionamiento, normalmente el byte de 8 bits, para especificar el tamaño del offset. En este contexto se puede llamar a veces dirección relativa.

En pocas palabras offset va a conseguir cada dirección de memoria de cada carácter y lo devolverá a la instrucción solicitada.
Con lea esta solicitud de direcciones por cada carácter se hace de forma automática.

 

 Por ultimo podemos hacer uso de librerias para la impresion de cadenas en pantalla:

1.7 COMPILADORES, PROCESO DE ENSAMBLADO Y LIGADO

Código Fuente: El código fuente es aquel que contiene las lineas de código escritas en el lenguaje de programación sobre el cual estamos trabajando.

 Sin embargo este código no es entendible por el ordenador dado su origen de solo reconocer instrucciones en lenguaje maquina (0 y 1) por lo tanto todo nuestro código solo es una maraña de símbolos raros para el ordenador, para poder ser reconocible todo lo escrito, el lenguaje de programación se vale de un programa llamado interprete o compilador (ya es cuestión del lenguaje), el cual traduce o interpreta vaya la redundancia todo nuestro código a lenguaje maquina, de esta manera se obtiene un archivo el cual es llamado: 

Código Objeto: archivo compuesto por un conjunto de datos escritos en un lenguaje de programación  de tipo binario o código maquina obtenidos de la traducción de un anterior código fuente. En la practica generalmente se genera un codigo intermedio, como lo es, ensamblador, es decir se transforma el codigo fuente a codigo ensamblador y posteriormente se traduce a lenguaje maquina.
En python por ejemplo podemos considerar a los archivos .pyc archivos de código objeto ya que el intérprete no puede leer directamente el texto en el archivo * .py, por lo que este texto se convierte primero en un código de bytes que está dirigido al PVM (no al hardware sino a PVM "Python Virtual Machine" ) . PVM ejecuta este código de bytes. *.
En resumen nuestro programa lo escribimos en el lenguaje de programación que deseamos y el compilador o interprete lo traduce en un archivo diferente para que la maquina pueda leerlos.

Y por ultimo, una vez que estamos completamente seguros que nuestro código funciona perfectamente es cuando creamos el ejecutable, es decir nuestro programa, pues deja decirte que un programa también es un archivo de texto el cual contiene las instrucciones finales de un programa, las cuales se tiene pensado ya no sera necesario modificar de manera que se codifican enteramente en lenguaje maquina es asi que obtenemos 

Código Ejecutable: es básicamente el programa final.
Si eres un usuario de windows el ejemplo mas sencillo de un código ejecutable son los archivos *.EXE.
 
Como podemos ver, el código final es mucho menos entendible que el código objeto, esto es debido a que se encuentra por una parte cifrado y por otra parte se encuentra escrito totalmente en  lenguaje maquina.
 
 
Compiladores y Ensambladores:
En fin, los ejemplos vistos anteriormente estan hechos con python, python es un lenguaje interpretado, es decir utiliza un interprete, el cual traduce las instrucciones a medida que estas son ingresadas.

Por otro lado, anteriormente, los primeros pioneros en la programación son los compiladores y ensambladores, ambos son considerados como traductores, esto es, traducen lo escrito en un archivo de texto a lenguaje maquina.

La principal diferencia entre compilador y ensamblador llega en el hecho de que generalmente los compiladores traducen un codigo a un lenguaje intermedio, como puede ser ensamblador, una vez que se hizo esto, se apoyan de esa traducción para tranformar el codigo a lenguaje maquina.

Por el contrario el ensamblador, lee tu codigo, te detecta errores, y si no tenemos errores traduce directamente a lenguaje maquina, es decir, hace una traducción directa.

Ambos utilizan lo que se conoce como ligadores o enlazadores, estos al traducir un formato ejecutable, generamente se topan con segmentos de codigo como las importaciones o llamadas a otros programas, es aqui donde ellos se encargan de enlazar los codigos y archivos faltantes para una correcta traducción a Lenguaje Maquina.

En resumen, el proceso que sigue un compilador o un ensamblador es:
1. El programa utiliza un editor de texto para crear un archivo de texto ASCII, conocido como archivo de código fuente.

2. El ensamblador lee el archivo de código fuete y produce un archivo de código objeto, una traducción del programa a lenguaje máquina. De manera opcional, produce un archivo de listado. Si ocurre un error, el programador debe regresar al paso 1 y corregir el programa.

3. El enlazador lee el archivo de código objeto y verifica si el programa contiene alguna llamada a los procedimientos en una biblioteca de enlace. El enlazador copia cualquier procedimiento requerido de la biblioteca de enlace, lo combina con el archivo de código objeto y produce el archivo ejecutable. De manera opcional, el enlazador puede producir un archivo de mapa.

4. La herramienta cargador (loader) del sistema operativo lee el archivo ejecutable y lo carga en memoria, y bifurca la CPU hacia la dirección inicial del programa, para que éste empiece a ejecutarse.

1.4 INTERRUPCIONES

CONCEPTO DE INTERRUPCIONES
Una interrupción es una situación especial que suspende la ejecución de un programa de modo que el sistema pueda realizar una acción para tratarla. Tal situación se da, por ejemplo, cuando un periférico requiere la atención del procesador para realizar una operación de E/S.
Las interrupciones constituyen quizá el mecanismo más importante para la conexión del microcontrolador con el mundo exterior, sincronizando la ejecución de programas con acontecimientos externos.


PASOS PARA EL PROCESAMIENTO
1. Terminar la ejecución de la instrucción máquina en curso.
2. Salva el valor de contador de programa, IP, en la pila, de manera que en la CPU, al terminar el proceso, pueda seguir ejecutando el programa a partir de la última instrucción.
3. La CPU salta a la dirección donde está almacenada la rutina de servicio de interrupción (ISR, Interrupt Service Routine) y ejecuta esa rutina que tiene como objetivo atender al dispositivo que generó la interrupción.
4. Una vez que la rutina de la interrupción termina, el procesador restaura el estado que había guardado en la pila en el paso 2 y retorna al programa que se estaba usando anteriormente.
Las interrupciones mas comunes son:
21h: Invoca a todos los servicios de llamada a función DOS, generalmente usado en convinacion con otros servicios para la entrada o salida de datos.
20h: Invoca al servicio de terminación de programa del DOS (termina un programa, como el exit).
10h: Despliega opciones de video
16h: Esta interrupción se encarga de controlar el teclado del PC

1.2 EL PROCESADOR Y SUS REGISTROS INTERNOS

Definición de registros:
un registro es una memoria de alta velocidad y poca capacidad, integrada en el microprocesador, que permite guardar transitoriamente y acceder a valores muy usados, generalmente en operaciones matemáticas.

Función de los registros:
• Los registros están en la cumbre de la jerarquía de memoria, y son la manera más rápida que tiene el sistema de almacenar datos. Los registros se miden generalmente por el número de bits que almacenan; por ejemplo, un "registro de 8 bits" o un "registro de 32 bits“.
• La CPU contiene un conjunto de localidades de almacenamiento temporal de datos de alta velocidad llamada registro. Algunos de los registros están dedicados al control, y solo la unidad de control tiene acceso a ellos. Los registros restantes son los registros de uso general y el programador es el usuario que tiene acceso a ellos.

El procesador 8086 esta dividido en los siguientes registros: 

La UCP o CPU tiene 14 registros internos, cada uno de ellos de 16 bits (una palabra). Los bits están enumerados de derecha a izquierda, de tal modo que el bit menos significativo es el bit 0. Los registros se pueden clasificar de la siguiente forma:
Registros de datos:
AX: Registro acumulador. Es el principal empleado en las operaciones aritméticas.
BX: Registro base. Se usa para indicar un desplazamiento.
CX: Registro contador. Se usa como contador en los bucles.
DX: Registro de datos. También se usa en las operaciones aritméticas.
Estos registros son de uso general y también pueden ser utilizados como registros de 8 bits, para utilizarlos como tales es necesario referirse a ellos como por ejemplo: AH y AL, que son los bytes alto (high) y bajo (low) del registro AX. Esta nomenclatura es aplicable también a los registros BX, CX y DX.
 
Registros de segmentos:
CS: Registro de segmento de código. Contiene la dirección de las instrucciones del programa.
DS: Registro segmento de datos. Contiene la dirección del área de memoria donde se encuentran los datos del programa.
SS: Registro segmento de pila. Contiene la dirección del segmento de pila. La pila es un espacio de memoria temporal que se usa para almacenar valores de 16 bits (palabras).
ES: Registro segmento extra. Contiene la dirección del segmento extra. Se trata de un segmento de datos adicional que se utiliza para superar la limitación de los 64Kb del segmento de datos y para hacer transferencias de datos entre segmentos.
Registros punteros de pila:
SP: Puntero de la pila. Contiene la dirección relativa al segmento de la pila.
BP: Puntero base. Se utiliza para fijar el puntero de pila y así poder acceder a los elementos de la pila.
Registros índices:
SI: Índice fuente.
DI: Índice destino.
 
 
Puntero de instrucciones:

IP: Registro puntero de instrucción o contador de programa (PC). Contiene el desplazamiento de la siguiente instrucción a ejecutar respecto al segmento de código en ejecución. Por lo tanto, la dirección completa de la siguiente instrucción sería CS:IP. La única forma de influir en este registro es de forma indirecta mediante instrucciones de bifurcación.
Registro de banderas (flags):
Cada bandera es un bit y se usa para registrar la información de estado y de control de las operaciones del microprocesador. Hay nueve banderas (los 7 bits restantes no se utilizan):
Banderas de estado: 
Registran el estado del procesador, normalmente asociado a una comparación o a una instrucción aritmética.
CF: Bandera de acareo.
OF: Bandera de desbordamiento (aritmético).
ZF: Bandera de resultado 0 o comparación igual.
SF: Bandera de resultado o comparación negativa.
PF: Bandera de paridad (número par de bits).
AF: Bandera auxiliar. Indica si hay necesidad de ajuste en las operaciones aritméticas con números
BCD.
Banderas de control:
DF: Bandera de dirección. Controla la dirección de las operaciones con cadenas de caracteres
incrementando o decrementando automáticamente los registros índices (SI y DI)
IF: Bandera de interrupciones. Indica si están permitidas o no las interrupciones de los dispositivos
externos.
TF: Bandera de atrape. Controla la operación de modo paso a paso (usada por el programa DEBUG).

1.1 MACROS Y PROCEDIMIENTOS DE EMU8086

Ya hemos visto que EMU8086 trabaja con interrupciones del procesador de esa arquitectura pero es posible trabajar con librerías que incluyen macros y procedimientos para hacer mas fácil la programación en el lenguaje ensamblador.

En esta ocasión les presentare los diferentes macros y procedimientos con su respectiva descripción de la librería EMU8086.

Macros

  • PUTC char - Macro con un parámetro. Imprime un carácter ASCII en la posición actual del cursor.
  • GOTOXY col, fila - Macro con dos parámetros. Establece la posición del cursos.
  • PRINT string - Macro con 1 parámetro. Imprime una cadena.
  • PRINTN string - Macro con un parámetro. Imprime una cadena. Lo mismo que PRINT pero agrega automáticamente "retorno de carro' al final de la cadena.
  • CURSOROFF - Apaga el cursor de texto.
  • CURSORON - Enciende el cursor de texto.

Para usar cualquiera de las macros anteriores, simplemente se escribe el nombre y los parámetros donde sea conveniente.

Procedimientos

  • PRINT_STRING: Procedimiento para imprimir una cadena terminada en nulo en la posición actual del cursor, recibe la dirección de la cadena en el registro DS: SI. Para usarlo declara: DEFINE_PRINT_STRING antes de la directiva END.
  • PTHIS: procedimiento para imprimir una cadena terminada en nulo en la posición actual de cursor (igual que PRINT_STRING), pero recibe la dirección de la cadena desde la pila. La cadena terminada a cero debe definirse justo después de la instrucción CALL. Por ejemplo:

    CALL PTHIS
    DB 'HELLO WORLD', 0
    Para usarlo declare: DEFINE_PTHIS antes de la directiva END.
  • GET_STRING: procedimiento para obtener una cadena terminada en nulo de un usuario, la cadena recibida se escribe en el búfer en DS: DI , el tamaño del búfer debe estar en DX . El procedimiento detiene la entrada cuando se presiona 'Enter'. Para usarlo declare: DEFINE_GET_STRING antes de la directiva END.
  • CLEAR_SCREEN: procedimiento para borrar la pantalla (que se realiza al desplazar la ventana completa de la pantalla) y establecer la posición del cursor en la parte superior. Para usarlo declare: DEFINE_CLEAR_SCREEN antes de la directiva END.
  • SCAN_NUM: procedimiento que obtiene el número FIRMADO de varios dígitos del teclado y almacena el resultado en el registro CX . Para usarlo declare: DEFINE_SCAN_NUM antes de la directiva END.
  • PRINT_NUM: procedimiento que imprime un número firmado en el registro AX . Para usarlo declare: DEFINE_PRINT_NUM y DEFINE_PRINT_NUM_UNS antes de la directiva END .
  • PRINT_NUM_UNS: procedimiento que imprime un número sin firma en el registro AX . Para usarlo declare: DEFINE_PRINT_NUM_UNS antes de la directiva END.
 Para utilizar cualquiera de los procedimientos anteriores, primero debe declarar la función en la parte inferior de su archivo (pero antes de END ), y luego usar la instrucción CALL seguida de un nombre de procedimiento.

Suma de dos números utilizando librería

Ahora veremos como se suma en el programa emu8086 utilizando librerías. Y aquí el código:

name "suma de dos numeros"
include "emu8086.inc"
org 100h

.data
suma db 2 dup (?)
.code
sumas proc
    print " Introduce el primer numero: "
    call scan_num
    mov suma[0],cl
    printn " "
    print " Introduce el segundo numero: "
    call scan_num
    mov suma[1],cl
    xor ax,ax
    add al,suma[0]
    add al,suma[1]
    printn " "
    print " La suma es: "
    call print_num
sumas endp
exit:
    print " "
    printn " "
    print "Presiona enter para salir..."
    mov ah,0  ;servicio de pulsación de teclado
    int 16h   ;invoca a servicios de taclado
    ret
define_print_string
define_print_num
define_print_num_uns
define_scan_num
end



Resta de dos números en emu8086 utilizando librerías

Aquí el código y las capturas del programa:

name 'resta dos numeros'
include 'emu8086.inc'
org 100h

.data
resta db 2 dup (?)

.code
restas proc
printn " "
print "Introduce el primer numero: "
call scan_num
mov resta[0],cl
printn " "
print "Introduce el segundo numero: "
call scan_num
sub resta[1],cl
printn ""
xor ax,ax
add al,resta[0]
add al, resta[1]
print " "
print "La resta es: "
call print_num
restas endp

exit:
printn " "
printn " "
print "Presiona enter para salir..."
mov ah,0
int 16h
ret
define_print_string
define_print_num
define_print_num_uns
define_scan_num
end



ret