Está en la página 1de 14

Programación – Lenguaje ensamblador

PROCESADOR DE ESTUDIO INTEL 8086/8088

Características generales

Procesadores creados hacia mediado y fines de los ’70. Son los primeros procesadores
de 16 bits, es decir, de longitud iniciaron la era de los procesadores x86. El 8088 fue
utilizado en la IBM PC (IBM Personal Computer o Computador Personal IBM). Ellos
tenías características muy similares, iguales en muchos casos, pero si se
diferenciaban en el bus de datos. El 8086 tenía un bus de datos de 16 bits y el 8088,
en cambio, de 8 bits.

El bus de direcciones en ambos procesadores es de 20 bits lo que permite trabajar


con 220 direcciones distintas, es decir, 1 Mega Direcciones. Como en la Memoria
Principal, cada una de ellas apuntaba a un dato de 8 bits, su capacidad máxima de
Memoria Principal es de 1Mbyte.

Grupo de instrucciones

Su set posee 89 instrucciones distribuido en los siguientes grupos:

• Transferencia de datos (14): movimiento de datos entre registros y/o Memoria


Principal

• Aritméticas (20): operaciones aritméticas de enteros

• Manipulación de bits (10): operaciones lógicas

• Cadenas (5): movimiento, búsqueda y comparación de cadenas de datos

• Transferencia de programa (29): saltos, llamadas

• Control del procesador (11): detención, depuración, IRQs

Tipos de datos

Puede trabajar con los siguientes tipos de datos:

• ASCII

• BCD

• Enteros sin signo

1
© Universidad de Palermo Prohibida la reproducción total o parcial de imágenes y textos.
• 8 bits: [0, 255]

• 16 bits: [0, 65535]

• Enteros con signo

• 8 bits: [-128, +127]

• 16 bits: [-32.768, +32.767]

• Cadenas secuencia de bytes o palabras (strings)

REGISTROS E INDICADORES DE ESTADO O BANDERAS (FLAGS)

Registros

Posee 14 registros de 16 bits que se detallan a continuación:

• 4 generales (Register): AX (Acumulator), BX (Base), CX (Count), DX (Data)

• 2 para índices (Index): SI (Source), DI (Destination)

• 3 para punteros (Pointers): SP (Stack), BP (Base), IP (Instruction)

• 4 para segmentos (Segment): DS (Data), CS (Code), ES (Extra), SS (Stack)

• 1 de banderas (Flags): indicadores de estado

Por ejemplo, el CS será el Code Segment, el DI será el Destination Index o el CX será


el Count Register.

Los registros que finalizan con “X” pueden ser tratados como un
todo, es decir operando con sus 16 bits (2 bytes), o pueden
operarse de a 1 byte. El byte menos significativo se denominará
con la letra final “L” (por Low) y el byte más significativo se
denominará con la letra final “H” (por High). Como ejemplo de
esto se puede ver como se suman dos operandos de 16 bits o dos
de 8 bits:

• ADD AX,CX  AX = AX + CX 16 bits

• ADD AH,CL  AH = AH + CL  8 bits

2
© Universidad de Palermo Prohibida la reproducción total o parcial de imágenes y textos.
Registros de banderas

Es un registro de 16 bits de los cuales no todos son utilizados. Este es el registro de


banderas:

• OF: Desbordamiento (Overflow Flag)  En “1” indica que hubo desbordamiento


aritmético

• DF: Dirección ("Direction Flag")  Controla el incremento de los registros índices


(SI, DI) en las operaciones con cadenas de caracteres

• IF: Interrupción ("Interrupt Flag")  En “1” habilita que el procesador atienda las
interrupciones de hardware enmascarables. En “0” las ignora

• TF: Trampa ("Trap Flag") En “1”, el procesador genera automáticamente una
interrupción del Tipo 1 después de la ejecución de cada instrucción para permitir
insertar código depurador de programa. Normalmente está en “0”

• SF: Signo ("Sign Flag") Es “1” si el resultado de la operación es negativo

• ZF: Cero ("Zero Flag") Es “1” si el resultado de la operación es cero o la


comparación entre dos registros o un registro y un valor dio que son iguales

• AF: Acarreo auxiliar (“Auxiliary Carry Flag”)  Indicador de acarreo entre bit 7 y
bit 8 de los registros AX, BX, CX y DX utilizado para el ajuste en operaciones
aritméticas en BCD (Binary Coded Decimals)

• PF: Paridad ("Parity Flag")  Si está en “1” indica un número par de unos en el
registro resultado de la operación

• CF: Acarreo ("Carry Flag")  Indicador de acarreo del bit más significativo que
puede ocurrir en las operaciones aritméticas de suma y resta

• Los bits con “-“ no tienen uso

Al utilizar el D.O.S. DEBUG para inspeccionar y modificar el contenido de los


registros, el valor que posee cada registro se verá de la siguiente manera:

AX=0000 BX=0000 CX=B0D5 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000


DS=17A9 ES=17A9 SS=17A9 CS=17A9 IP=0100 NV UP EI PL NZ NA PO NC

Nótese que se indican todos los registros antes mencionados junto con su contenido
en hexadecimal después del “=” excepto las banderas. Se pueden ver 8 de las 9
banderas antes descriptas pero en lugar de ver su valor con “0” o “1” existen pares
de letras cuyo significado se detalla a continuación:

3
© Universidad de Palermo Prohibida la reproducción total o parcial de imágenes y textos.
Bit Indicador Si su valor es “1” Si su valor es “0”

CF Acarreo CY ("Carry Yes") NC ("No Carry")

PF Paridad PE ("Parity Even") paridad par PO ("Parity Odd") paridad impar

AF Acarreo auxiliar AC ("Auxiliary Carry") NA ("No Auxiliary Carry")

ZF Cero ZR ("Zero") NZ ("Non Zero")

SF Signo NG ("Negative") PL ("Plus")

IF Interrupción EI ("Enabled Interrupts") DI ("Disabled Interrupts")

DF Dirección DN ("Down") UP (“Up”)

OF Desbordamiento OV ("Overflow") NV ("Non Overflow")

El flag o bandera de trampa TF no es accesible desde el D.O.S. DEBUG en forma


directa. Se lo podrá leer y modificar mediante un programa en lenguaje ensamblador.

DIRECCIONAMIENTO DE MEMORIA

El direccionamiento que la UCP genera a través de su bus de direcciones posee 20


bits. Se podrán direccionar 220 posiciones diferentes en la Memoria Principal, por
ejemplo. Pero Intel resuelve como direccionar 20 bits con registros de 16 bits ya que
no hay otra posibilidad dentro de la UCP.

Para ello, tratará el espacio de direccionamiento como un Espacio Segmentado.


Estos es que las direcciones absolutas que van desde 00000h hasta FFFFFh de 20 bits
deberán manejarse con dos pares de 16 bits. Al primer conjunto de direccionamiento
lo llama Segmento (Segment) y al otro conjunto Deslazamiento (Offset). Por lo tanto
toda dirección de memoria estará conformada por este par de valores de 16 bits cada
uno, Segmento:Desplazamiento (Segment:Offset).

Para esto, Intel define que cada segmento será de 64K posiciones de memoria, es
decir, de 0000h a FFFFh, que son 16 bits. Dentro de cada segmento se podrá
“direccionar” cada posición de memoria a través del Desplazamiento.

A las primeras 64K direcciones formarán parte del Segmento 0, es decir, las primeras
64K direcciones se podrán encontrar desde 0000:0000 hasta 0000:FFFF, todos valores
hexadecimales. La posición cero será 0000:0000, la 1 será 0000:0001 y así
sucesivamente.

El segundo Segmento o Segmento 1 no comienza a continuación de donde termina el


Segmento 0, sino que comienza 16 bytes más adelante, es decir, el segmento 1
comienza en la posición 16 de memoria que según lo anterior es la 0000:0010 (en
hexa).

4
© Universidad de Palermo Prohibida la reproducción total o parcial de imágenes y textos.
De esta manera, la posición absoluta 16 (00000h) de la memoria es, según el segmento
0, la dirección 0000:0010, si nos referimos desde el segmento 1 será 0001:0000. La 17
será 0001:0001, la 18 0001:0002 y así sucesivamente.

Como podemos ver, una misma dirección absoluta de memoria puede tener más de
una dirección segmentada o relativa al segmento que se tome como referencia.

En la figura se muestra la segmentación del espacio de direccionamiento tal como se


comentó recientemente.

Veamos por ejemplo la posición de memoria absoluta 6.250 = (0186Ah). ¿Cómo podré
direccionarla en la memoria segmentada? Tomemos el ejemplo de direccionamiento
tomando como base los segmentos 0,1, 2 y 3.

• Desde el segmento 0 será = 0000:186A, el desplazamiento se marca con 

• Desde el segmento 1 será= 0001:185A, el desplazamiento se marca con 

• Desde el segmento 2 será= 0002:184A, el desplazamiento se marca con 

• Desde el segmento 3 será= 0003:183A, el desplazamiento se marca con 

Ahora bien, ¿cómo podemos calcular la dirección absoluta de cualquier dirección


segmentada? Se debe hacer lo siguiente:

• Multiplicando el valor del segmento por 16d o 10h, es decir, se lo desplaza hacia la
izquierda inyectando un “0” por derecha

• Sumándole ahora el valor del desplazamiento

Ejemplo: 12B4:8765

• 12B4h * 10h = 12B40h

5
© Universidad de Palermo Prohibida la reproducción total o parcial de imágenes y textos.
• 12B40h + 8765h = 1B2A5h

Entonces diremos que 1B2A5h y 12B4:8765 son la misma posición de memoria.

CONCEPTO DE LENGUAJE DE BAJO NIVEL E INTRODUCCIÓN AL LENGUAJE


ENSAMBLADOR

Para poder programar nuestro procesador 8086/8088 necesitaríamos hacerlo


mediante bits y bytes, escribiendo las instrucciones en binario. Esto sería demasiado
arduo e ineficiente, por eso se crea el lenguaje Ensamblador (Assembler) a partir de
los códigos binarios que proporciona el fabricante Intel para cada una de sus
instrucciones, en donde se le asigna a cada una de ellas un símbolo. Por eso se lo
denomina un lenguaje “Simbólico del lenguaje de máquina”.

Por ejemplo, la instrucción para mover un dato al registro AX posee un código de


operación que es 87h. Si quisiera escribir “cargar el AX con el valor 34B0h” debiera
indicarle al procesador lo siguiente 87B034h. En lugar de eso, podría escribir MOV AX,
34B0 y que un intérprete lo traduzca al binario. Esta última escritura se ha realizado
en lenguaje Ensamblador.

Utilizaremos el D.O.S. DEBUG como herramienta para codificar en lenguaje


ensamblador (de ahora en adelante assembler), para editar los registros del
ordenador y ejecutar los programas paso a paso o en bloque. Existen otras
herramientas mucho más poderosas para escribir un programa en assembler y que
luego termine convirtiéndose en binario como ser el Macro Assembler de Microsoft™ o
el Turbo Assembler de Borland™. Estas herramientas permiten escribir el programa
fuente en assembler en un procesador de textos (Source Code) para luego compilarlo
(Object Code) y linkeditarlo (Executable Code) y así obtener un archivo ejecutable en
D.O.S.

PROGRAMACIÓN Y DEPURACIÓN UTILIZANDO EL DEPURADOR DEL D.O.S. (D.O.S.


DEBUG)

El D.O.S. DEBUG

Como comentamos en el punto anterior, utilizaremos esta herramienta para codificar


en Assembler nuestros programas y luego para ejecutarlos y depurarlos. Pare ello
veremos paso a paso como realizarlo.

Acceso al DEBUG

Procesadores de 32 bits o menos

• Desde el escritorio del Windows, presionar botón <Inicio> y tipear “cmd”

• Una vez abierta una ventana con el símbolo del sistema, tipear “debug” y
presionar <Enter>

• Se mostrará un “signo menos” como línea de comando del DEBUG

6
© Universidad de Palermo Prohibida la reproducción total o parcial de imágenes y textos.
• Para salir del debug tipear “q” y presionar <Enter>

Procesadores de 64 bits – Instalación de la máquina virtual DOSBox

• Descargar el archivo “Tasm_1.4_Windows_7-


Windows_8_64_bit_Techapple.net.txt”

• Alterar su extensión y cambiar el “.txt” final por “.exe”. Si no puede ver las
extensiones de los archivos debe buscar la opción “Cambiar opciones de carpeta y
bpusqueda” y en la solapa <Ver> ubicar la marca “Ocultar las extensiones de
archivos ara tipos e archivos conocidos” y desmarcarla. Presionar <Aplicar> y
<Aceptar>. Ahora debieran verse.

• Ejecutar el archivo .EXE recientemente renombrado. Esta herramienta instalará


una máquina virtual D.O.S. Box en el disco C:

• Posicionarse en la carpeta “C:\Tasm 1.4\Techapple.net”

• Editar con el Notepad o Block de Notas el archivo “tasmmounted.conf”

• Ir al final y después de “# You can put your MOUNT lines here.“, verificar que
existan las siguientes líneas; sino, agregarlas

o mount C: "c:\Tasm 1.4\"


o c:
o cd tasm
o path %path%;c:\tasm
o Grabar el archivo tasmmounted.conf”

• Descargar el archivo “debug.txt”

• Renombrarlo como “debug.exe” tal como se explicó antes

• Mover el archivo “debug.exe” a la carpeta “C:\Tasm 1.4\Tasm”

• Arrancar la máquina virtual desde el escritorio a través del ícono y deberá


verse la siguiente pantalla:

7
© Universidad de Palermo Prohibida la reproducción total o parcial de imágenes y textos.
• Estamos en condiciones de comenzar a trabajar con el DEBUG tipeando “debug” y
presionando <Enter>

Utilizando el DEBUG

Una vez ejecutado el programa DEBUG, aparecerá el símbolo “-“ como indicador para
tipear los comandos del DEBUG como se muestra en la siguiente pantalla:

Comandos del DEBUG

En la sintaxis de cada comando, encontraremos la orden específica y entre corchetes


“[“ y “]” los operandos opcionales. Los siguientes comandos serán los fundamentales
para la resolución de los ejercicios propuestos.

Todos los comandos del DEBUG deben tipearse y finalizarse presionando el <Enter>.

8
© Universidad de Palermo Prohibida la reproducción total o parcial de imágenes y textos.
Q (Quit)

SINTAXIS: q

Tipeando “q” o “Q” se vuelve a la línea de comandos del D.O.S. Para salir del D.O.S y
la máquina virtual se debe tipear “exit” y presionar <Enter>.

R (Register)

SINTAXIS: r [nombre del registro]

Tipeando “r” o “R” se podrá ver el contenido de todos los registros y debajo de ellos
se ve la posición de memoria donde apunta en contador de programa y cuál es la
instrucción que en ese lugar existe.

Para alterar el contenido de un registro cualquiera deberá tipearse “r” y dejando un


espacio el registro que se desea modificar. El debug mostrará el contenido y pedirá se
ingrese un nuevo valor. Si coloca el nuevo valor y se presiona luego <Enter>. Si no se
colocó ningún valor nuevo se mantiene el existente.

D (Dump)

SINTAXIS: d [rango]

Recordando que nuestro procesador es de arquitectura Von Neumann, en la Memoria


Principal podrán alojarse tanto datos como instrucciones. Por lo tanto, tendremos dos
comandos distintos para poder interpretar el contenido binario de la memoria como si
fueran datos o instrucciones. Este comando “D” interpreta el contenido de la
memoria como si fuesen datos binarios y lo muestra en pantalla.

Si no se coloca ningún rango mostrará el contenido de la memoria desde la posición


DS:0100 un total de 128 bytes en 8 renglones de 16 bytes cada uno. A la derecha se
mostrará el grafo correspondiente al código ASCII, en la medida de que sean
caracteres imprimibles en pantalla; de no ser así, mostrará un “.” Punto.

9
© Universidad de Palermo Prohibida la reproducción total o parcial de imágenes y textos.
Se puede pedir ver un rango de “N” bytes a partir de una dirección específica hasta
otra dirección.

E (Edit)

SINTAXIS: e dirección [lista]

Con este comando, se podrá modificar el contenido de posiciones de memoria de a


una o de a varias a través de una cadena de caracteres (String).

dirección = es la locación de memoria desde donde se ingresarán los datos a


modificar
lista = conjunto de datos a ingresar en la locación de memoria como una cadena
sucesiva de bytes

Si se usa solo la dirección, se editarán los datos byte por byte de la siguiente
manera. Se cambiará el dato que está en la dirección DS:0204. Primero se muestra la
memoria antes del cambio y luego después del cambio. Al tipear “e 204” se muestra
el contenido que es “3Ch” y aparece un guión titilante para tipear el dato que se
quiere colocar en esa posición de memoria. Si tipeamos “45h” y presionamos <Enter>
el dato se habrá modificado.

Si en lugar de presionar <Enter> una vez ingresado el dato nuevo, presionamos la


<Barra espaciadora>, se cambiará el dato que colocamos recién y se pasará a editar el
siguiente. Se puede continuar editando con la <Barra espaciadora> y finalizar la
edición con <Enter>.

10
© Universidad de Palermo Prohibida la reproducción total o parcial de imágenes y textos.
En cada flecha “amarilla” se presionó la <Barra espaciadora> y en la flecha “Naranja”
se presionó <Enter>. Se pueden ver las posiciones de memoria cambiadas recuadradas
en “verde”.

Para usar la lista se ingresará la dirección de inicio y la cadena de caracteres entre


comillas dobles, como se ve en la figura:

Primeramente se muestran 128 bytes de la memoria y recuadrado en “rojo” las


posiciones de memoria que se modificarán. Luego se ingresa el comando (flecha
“amarilla”) y luego se ven alteradas las posiciones de memoria recuadradas en
“verde”.

A (Assemble)

SINTAXIS: a [dirección]

Con este comando se ensamblan los mnemónicos del 8088/8086 en la memoria, es


decir, este comando se utiliza para crear código de máquina ejecutable (binario) a
partir de sentencias en lenguaje assembler. Todos los valores numéricos son
hexadecimales y sólo pueden tener de 1 a 4 dígitos.

dirección = es la locación de memoria desde donde se ingresarán las instrucciones


en assembler. Si no se coloca nada, se comenzará de la posición CS:0100 y se
ensamblo código antes, continuará de la siguiente posición de memoria posterior a la
última instrucción ingresada.

Las instrucciones en assembler tienen la siguiente sintaxis:

• MNEMONICO 1er PARAMETRO, 2do PARAMETRO


( destino ), ( origen )

Que se traducirán en binario según el formato:

• CÓDIGO DE OPERACION 1er OPERANDO, 2do OPERANDO

11
© Universidad de Palermo Prohibida la reproducción total o parcial de imágenes y textos.
Si tipeamos MOV AX, 1234 se ingresará en binario B83412. El código de operación
para mover datos la registro AX en forma inmediata es B8 y el dato se guarda en
Little endian siendo 1234h guardado como 3412.

Cuando se inicie el modo “ensamblado” se hará por ejemplo tiepando “a 100” y


presionando <Enter>. A medida que se ingresan las instrucciones se confirmarán
presionando <Enter>. Si no se ingresa nada y se vuelve a presionar <Enter> se vuelve a
la línea de comando del DEBUG.

A medida que ingresamos las instrucciones vemos cómo se van incrementando las
posiciones de memoria en función de los bytes que ocupa cada instrucción.
Recordemos que esta arquitectura tiene instrucciones de longitud variable por ser
CISC (Complex Instruction Set Computing). Veamos el siguiente ejemplo:

Vemos que la primera instrucción comienza en 073F:0100 y la segunda en 073F:0103,


quiere decir que ocupó 3 bytes, el 100, el 101 y el 102. En cambio la instrucción “JZ
130” ocupa 2 bytes porque comienza en la 073F:010C y termina en la 073F:010D ya
que la próxima comienza en la 073F:010E.

U (Unassemble)

SINTAXIS: a [rango]

Desensambla los bytes y muestra su lista de código fuente en forma mnemónica y


binaria con sus direcciones y valores. Tipeando “u” solamente se desensamblarán 20h
bytes (32 posiciones).

12
© Universidad de Palermo Prohibida la reproducción total o parcial de imágenes y textos.
Podemos ver como se listaron instrucciones desde la posición 073F:0100 hasta la
011F, 20 bytes. También podemos ver a la derecha de cada una de las direcciones de
memoria los respectivos binarios de cada instrucción. Por ejemplo “INC AX” ocupa
solo 1 byte.

Para usar el rango, podremos listar las instrucciones desde una posición y por una
cantidad de bytes específica, como por ejemplo, lo siguiente:

Vemos que el comando “u 0100 L 12” listará los 12h bytes a partir de la dirección
CD:0100 mostrándolo como instrucciones. Este comando tiene el mismo efecto que
tipear “u 100 112”.

T (Trace)

SINTAXIS: t [=dirección] [cantidad]

Ejecuta una instrucción a la vez y muestra el contenido de todos los registros, la


condición de las banderas y la siguiente instrucción a ejecutar. Veamos el ejemplo:

Podemos ver que se ejecutaron una cantidad de 3 instrucciones desde la dirección


CS:0100 que son las de las posiciones 100, 103 y 106. Luego frena la ejecución en la
108 (sin ejecutarla).

Si se usa este comando en las sentencias CALL (llamado a subrutina) o INT (llamado a
subrutina de interrupción) se depurarán las subrutinas entrando instrucción por
instrucción en ellas. Lo mismo ocurrirá con la sentencia LOOP (bucle) que permitirá

13
© Universidad de Palermo Prohibida la reproducción total o parcial de imágenes y textos.
dar seguimiento a cada paso del bucle hasta que CX sea = 0. Más adelante se verán
ejercicios con estos casos.

P (Proceed)

SINTAXIS: t [=dirección] [cantidad]

Ejecuta una instrucción a la vez y muestra el contenido de todos los registros, la


condición de las banderas y la siguiente instrucción a ejecutar. La diferencia con
“Trace” es que no depura las subrutinas definidas con CALL e INT, las ejecuta como
una “caja negra” es decir, como una única instrucción sin ir paso a paso dentro de
ellas.

G (Go)

SINTAXIS: t [=dirección] [punto de ruptura]

Ejecuta el programa que está guardado en la memoria. El parámetro dirección, si


se coloca, indicará la posición de memoria en donde comenzará a ejecutarse el
programa. Si no se coloca comenzará desde la posición apuntada por el CS y el IP
(CS:IP) también llamado contador de programa. El DEBUG frenará cuando encuentre
un INT 20 restableciendo el IP en 0100.

El punto de ruptura se utiliza para que la unidad de ejecución frene en esa posición.
Vemos en el ejemplo:

Aquí primero con el comando “u” mostramos el programa. Luego con el comando “g
=cs:0108 cs:010E” la unidad de control comienza la ejecución del programa en la
CS:0108 y finaliza en la CS:010E sin ejecutarla. Este comando no muestra los registros
ni pasos intermedios desde el inicio de la ejecución hasta el final o punto de ruptura.

14
© Universidad de Palermo Prohibida la reproducción total o parcial de imágenes y textos.

También podría gustarte