CERRAR VENTANA

+ Responder Tema
Página 1 de 2 1 2 ÚltimoÚltimo
Resultados 1 al 10 de 13

Tema: (tutorial) ensamblador y programacion

  1. #1
    Administrator
    Puntos: 7,271, Nivel: 56
    Nivel completado: 61%, Puntos necesarios para el proximo Nivel: 79
    Actividad total: 10.1%
    Logros:
    100 Experience Points250 Experience Points500 Experience Points1000 Experience PointsRecommendation Second Class
    Charly tiene un aura espectacular Charly tiene un aura espectacular Charly tiene un aura espectacular Avatar de Charly
    Fecha de Ingreso
    Apr 2008
    Ubicación
    tigre. Bs.As Arg
    Edad
    33
    Mensajes
    1,362
    Puntos
    7,271
    Nivel
    56
    Gracias
    9
    Agradecido 1 Time in 1 Post

    Predeterminado (tutorial) ensamblador y programacion

    la verdad no se si servira de algo pero encontre este tutorial de programacion. me paresio muy interesante despues si alguno entiende me dice si sirve para algo

    Tutorial Ensamblador
    Parte 1: Introducción


    Este tutorial es para aquellos que no están familiarizados con el lenguaje ensamblador, o tienen una idea lejana. Por supuesto que si tiene conocimientos de otros lenguajes de programación (Basic, C/C++, Pascal...) seguro que le serán de gran utilidad.

    Pero incluso si esta familiarizado con el ensamblador, es todavÃÂ*a una buena idea echarle una ojeada a este tutorial para aprender la sintaxis del Emu8086.
    Asumiremos que tiene ciertos conocimientos de representación de números en diferentes sistemas de numeración y de las operaciones que puede realizar con ellos, tanto aritméticas como lógicas, de lo contrario se recomienda que lea el tutorial sobre sistemas de numeración antes de continuar.
    ¿Qué es un Lenguaje Ensamblador?
    Un Lenguaje Ensamblador es un lenguaje de programación de bajo nivel. Necesitaremos ciertos conocimientos sobre la arquitectura de un computador para comprender ciertas cuestiones. El modelo más simplificado se representa de la siguiente manera:



    El bus del sistema (en Amarillo en el esquema) conecta los diferentes componentes del ordenador.
    La CPU es el cerebro del ordenador, la mayor parte de los cálculos se realizan en su interior.

    La memoria RAM es el lugar donde se cargan los programas para posteriormente ser ejecutados.

    Dentro de la CPU


    REGISTROS de PROPÓSITO GENERAL

    La CPU de un 8086 tiene 8 registros de propósito general, y cada registro tiene su propio nombre:

    · AX – Es el registro acumulador (accumulator) (dividido en dos partes AH / AL).
    · BX - Es el registro de dirección base (base adress) (dividido en dos partes BH / BL).
    · CX - Es el registro contador (count) (dividido en dos partes CH / CL).
    · DX – Es el registro de datos (data) (dividido en dos partes DH / DL).
    · SI – Es el registro ÃÂ*ndice fuente (source index).
    · DI – Es el registro ÃÂ*ndice destino (destination index).
    · BP – Es el puntero base (base pointer).
    · SP – Es el puntero de la pila (stack pointer).

    A pesar del nombre del registro, es el programador el que determina el uso que se leva a dar a cada uno de los registros de propósito general. El principal propósito de un registro es contener un número (variable). El tamaño de los registros citados es de 16 bits, por ejemplo: 0011000000111001b (en binario), o 12345 (en decimal).

    Hay 4 registros de propósito general (AX, BX, CX, DX) formados por el conjunto de dos registros separados de 8 bits, por ejemplo si consideramos que tenemos almacenado en AX= 0011000000111001b, entonces tendremos en AH=00110000b y almacenaremos en AL=00111001b. Por lo tanto si modificamos cualquiera de los dos registros de 8 bits actualizaremos automáticamente el registro de 16 bits y viceversa. Lo mismo sucede con los otros 3 registros, donde "H" significa parte alta (high) y "L" parte baja (low) del registro.

    Como los registros están situados dentro de la CPU, es obvio que son de acceso mucho más rápido que la memoria. Acceder a una determinada localización (dirección) de memoria requiere el uso del bus del sistema, tardando más tiempo. Acceder a un dato situado en un registro apenas necesita tiempo. Por lo tanto deberemos de guardar los datos (variables) en la medida de lo posible en los registros. El conjunto de registros es pequeño, y alguno de ellos esta reservado para uso especifico lo cual limita nuestras posibilidades de almacenamiento de datos y variables, pero son un excelente lugar para almacenar los datos que son resultados intermedios de nuestros cálculos.

    REGISTROS de SEGMENTO
    · CS – Apunta al segmento que contiene el programa actualmente en ejecución.

    · DS – Apunta al segmento donde están definidas nuestras variables.
    · ES – Apunta a un segmento extra, el programador definirá su uso.
    · SS – Apunta al segmento que contiene la pila.
    Aunque es posible almacenar cualquier dato en los registros de segmento, no es una Buena idea. Los registros de segmento tienen un propósito especial, que es apuntar a los bloques accesibles de la memoria.
    Los registros de segmento trabajan en combinación con los registros de propósito general para acceder a cualquier posición de la memoria. Por ejemplo si queremos acceder a la posición fÃÂ*sica de memoria 12345h (hexadecimal), deberemos ajustar el valor del registro DS = 1230h y el valor del registro SI = 0045h. Esto es aconsejable ya que de esta manera podremos acceder (direccional) bastante más memoria que con un único registro que esta limitado a valores de 16 bits.
    La CPU realiza un calculo para situar esta dirección fÃÂ*sica: multiplica el valor del registro de segmento por 10h y le añade el valor almacenado en el registro de propósito general (1230h * 10h + 45h = 12345h):



    La dirección construida gracias a los valores de dos registros se denomina dirección efectiva de memoria (effective address).

    Por defecto los registros BX, SI y DI trabajan combinados con el registro de segmento DS; mientras que los registros
    BP y SP trabajan en combinación con el registro de segmento SS.
    Los demás registros de propósito general no sirven para formar direcciones efectivas de memoria.
    Ademas aunque el registro BX puede formar una direccion efectiva de memoria, los registros que lo forman que son BH y BL no pueden realizar dicha tarea.

    REGISTROS de PROPOSITO ESPECIAL

    · IP – es el puntero de instrucciones (instruction pointer).
    · Flags Register – es el registro de Banderas (Flags) que determina el estado actual del procesador.

    El registro IP siempre trabaja en combinacion con el registro de segmento CS de manera que apuntan a la instruccion que se esta ejecutando actualmente.
    El registro de banderas (Flags Register) es modificado automaticamente por la CPU despues de cada operacion matematica o logica, lo que permite determinar el tipo de resultado y ademas permite indicar las condicones para transferir el control a otras partes del programa.

    No puede accederse al contenido de estos registros de forma directa.

    sigue son muchos mas.

    El comentar no Produce ninguna enfermedad infectocontagiosa,
    valora el esfuerso de los que postean y comenta!!!
    gracias


  2. #2
    Administrator
    Puntos: 7,271, Nivel: 56
    Nivel completado: 61%, Puntos necesarios para el proximo Nivel: 79
    Actividad total: 10.1%
    Logros:
    100 Experience Points250 Experience Points500 Experience Points1000 Experience PointsRecommendation Second Class
    Charly tiene un aura espectacular Charly tiene un aura espectacular Charly tiene un aura espectacular Avatar de Charly
    Fecha de Ingreso
    Apr 2008
    Ubicación
    tigre. Bs.As Arg
    Edad
    33
    Mensajes
    1,362
    Puntos
    7,271
    Nivel
    56
    Gracias
    9
    Agradecido 1 Time in 1 Post

    Predeterminado (tutorial) ensamblador y programacion

    Tutorial Ensamblador

    Parte 2: Compilando Código




    Simplemente debemos escribir el código dentro del área de texto, y hacer clic sobre el botón [Compile]. El programa preguntara por la carpeta donde desea usted guardar el fichero con el código compilado. Si ha habido éxito en la compilación podremos pulsar el botón [Emulate] para cargar el fichero compilado en el emulador de un 8086.

    Directivas para el tipo de fichero generado:

    #MAKE_COM#

    #MAKE_BIN#

    #MAKE_BOOT#

    #MAKE_EXE#

    Podemos insertar estas directivas en el código fuente para especificar el tipo de fichero de salida deseado. Solo si el compilador no encuentra alguna de estas directivas le preguntara por el tipo de fichero de salida antes de que sea creado.

    Descripción de los diferentes tipos de ficheros generados:

    #MAKE_COM# - el formato mas simple y tradicional es crear un fichero que sea ejecutable, estos fichero se cargaran, dejando una zona libre, en la posición 100h (256 bytes).

    Seleccione Clean en el menú New si desea compilar a un fichero de tipo COM. La directiva de compilación ORG 100h deberá ser añadida antes del código a compilar. La ejecución siempre empieza desde el primer byte del fichero. Podrá ser ejecutado en el sistema operativo DOS o desde el Prompt de Windows.

    · #MAKE_EXE# - es un formato de fichero ejecutable mas avanzado. No estará limitado en tamaño, ni en el número de segmentos que use. El segmento Stack (que usara la pila) deberá ser definido dentro del programa. Podremos seleccionar EXE Template en el menú New para crear un programa simple de tipo EXE, con segmentos de datos, código y pila perfectamente definidos.
    El punto de comienzo de la ejecución dentro del código será definido por el programador. Podrá ser ejecutado en el sistema operativo DOS o desde el Prompt de Windows.


    · #MAKE_BIN# - Es un fichero ejecutable simple. Podremos definir los valores de todos los registros, segmento y offset del área de memoria donde este fichero será cargado. Cuando se cargue un fichero como "MI.BIN" en el emulador este buscara un fichero de tipo "MI.BINF" , y cargara "MI.BIN" en la localización especifica de memoria especificada en el fichero "MI.BINF", y también ajustara los valores de los registros usando información de dicho fichero (sugerencia: abra este fichero en un editor de texto para comprobar su contenido).
    En el caso de que el emulador no sea capaz de encontrar un fichero del tipo "MI.BINF", usara los valores contenidos en el momento actual dentro de los registros y el fichero "MI.BIN" será cargado en la dirección de memoria dada por CS:IP.
    El punto de ejecución comienza desde el valor marcado por CS:IP. Este tipo de fichero es exclusivo de este programa emulador.

    El fichero .BINF se crea automáticamente por el compilador si encuentra la directiva de compilación #MAKE_BIN#.
    AVISO cualquier fichero de tipo ".binf" existente será sobrescrito.

    Ejemplo del contenido de un fichero de información binario:

    #LOAD_SEGMENT=1234#

    #LOAD_OFFSET=0000#

    #AL=12#

    #AH=34#

    #BH=00#

    #BL=00#

    #CH=00#

    #CL=00#

    #DH=00#

    #DL=00#

    #DS=0000#

    #ES=0000#

    #SI=0000#

    #DI=0000#

    #BP=0000#

    #CS=1234#

    #IP=0000#

    #SS=0000#

    #SP=0000#

    Todos los valores deberán estar en HEX.

    Si no se especifica los siguientes valores se ajustan por defecto:
    LOAD_SEGMENT = 0100
    LOAD_OFFSET = 0000
    CS = ES = SS = DS = 0100
    IP = 0000

    Si LOAD_SEGMENT y LOAD_OFFSET no se definen, entonces se usan los valores que tengan CS e IP y vice-versa.

    En el caso de que el valor de Load to offset no sea cero (0000), la directiva ORG ????h deberá ser añadida al código fuente del fichero .BIN, donde ????h será el desplazamiento de carga (loading offset), Deberemos hacer esto para permitir que el compilador calcule correctamente las direcciones de memoria.

    · #MAKE_BOOT# - este tipo de fichero es una copia de la primera pista (track) de un disquete (floppy), también llamada sector de arranque (boot sector).
    Podra escribir el sector de arranque (boot sector) de un floppy virtual que se denominara (FLOPPY_0) desde el menú del emulador:
    [Virtual Drive] -> [Write 512 bytes at 7C00 to Boot Sector]
    Primero deberá compilar un fichero ".boot" y cargarlo en el emulador (vea los ejemplos "micro-os_loader.asm" y "micro-os_kernel.asm" en la carpeta "Samples" para mas información).

    Seleccione después en el menú [Virtual Drive] -> [Boot from Floppy] para arrancar el emulador desde un floppy virtual.

    Si tiene interés puede escribir el floppy virtual en un floppy real y arrancar su equipo desde el. Se aconseja usar "RawWrite for Windows" en la siguiente dirección: Solo los usuarios registrados pueden ver los links. Registrarse aquí
    (tenga cuidado que el fichero de ejemplo “micro-os_loader.asm" no usa un sector de arranque compatible con MS-DOS, luego es mejor usar un floppy vacÃÂ*o aunque deberá estar formateado en modo IBM (MS-DOS).
    La directiva de Compilación ORG 7C00h deberá ser añadida antes del código, y cuando arranca el ordenador carga la primera pista del floppy en la dirección efectiva 0000:7C00.
    El tamaño de un fichero .BOOT debe ser menor que 512 bytes (que es el limite de tamaño de un sector del floppy).
    La Ejecución de código siempre comienza desde el primer byte del fichero.
    Este tipo de fichero es exclusivo de este Emulador (Emu8086).

    Procesamiento de Errores



    El Compilador informa de los errores aparecidos durante la compilación del código fuente en una ventana independiente como la que sigue



    MOV DS, 100 - es una instrucción ilegal ya que los registros de segmento no pueden ser ajustados directamente, siendo necesario utilizar un registro de propósito general como puente intermedio:
    MOV AX, 100
    MOV DS, AX

    MOV AL, 300 - es una instrucción ilegal ya que el registro AL solo tiene 8 bits, y el valor máximo que puede almacenar es 255 (o 11111111b), y el mÃÂ*nimo es -128.

    El Compilador realiza varias pasadas antes de generar el código maquina correcto, y si encuentra un error y no realiza el numero total de pasadas puede mostrar mensajes de incorrecciones o errores. Por ejemplo:

    #make_COM#
    ORG 100h
    MOV AX, 0
    MOV CX, 5
    m1: INC AX
    LOOP m1 ; (no es un error real)
    MOV AL, 0FFFFh ; (el error esta aqui)
    RET

    Lista de errores generada:

    (7) Condition Jump out of range!: LOOP m1

    [Condición de salto fuera de rango]
    (9) Wrong parameters: MOV AL, 0FFFFh

    [Parametros incorrectos]
    (9) Operands do not match: Second operand is over 8 bits!
    [Los operandos no casan, el Segundo supera los 8 bits]


    El primer mensaje de error es incorrecto (7), ya que el compilador no ha terminado de calcular los offsets de las direcciones para las labels (etiquetas), y supone que el offset de la etiqueta m1 es 0000, y esa dirección esta fuera de rango ya que se supone que nosotros estamos comenzando la carga del código con un offset de valor 100h.

    Realicemos la siguiente corrección en la lÃÂ*nea: MOV AL, 0FFFFh (AL no puede contener el valor 0FFFFh). Esto soluciona ambos errores. Por lo tanto:

    #make_COM#

    ORG 100h

    MOV AX, 0

    MOV CX, 5

    m1: INC AX

    LOOP m1 ; sin error con el mismo código



    MOV AL, 0FFh ; solucionado!

    RET

    Cuando salvamos un fichero compilado, el compilador también salva otros dos ficheros que son utilizados por el Emulador para mostrar el código actual cuando le damos a la tecla run, pudiendo observar le emulación de cada lÃÂ*nea de código fuente en ensamblador

    *.~asm – este fichero contiene el código fuente original (source code) que ha sido utilizado para generar un fichero ejecutable.
    *.debug – este fichero tiene información que permite al emulador resaltar las lÃÂ*neas del código fuente original cuando emulamos el código maquina.
    *.symbol – Es la Tabla de SÃÂ*mbolos (Symbol Table), que contiene información que permite observar las variables del código en una ventana de "Variables". Es un fichero de texto que podremos abrir con cualquier editor de texto.
    *.binf - este fichero tiene información que es usada por el emulador para cargar un fichero de tipo BIN en una localización especifica de la memoria, y ajusta los valores del juego de registros antes de la ejecución; (creado solo si el fichero ejecutable generado es de tipo BIN).

    El comentar no Produce ninguna enfermedad infectocontagiosa,
    valora el esfuerso de los que postean y comenta!!!
    gracias


  3. #3
    Administrator
    Puntos: 7,271, Nivel: 56
    Nivel completado: 61%, Puntos necesarios para el proximo Nivel: 79
    Actividad total: 10.1%
    Logros:
    100 Experience Points250 Experience Points500 Experience Points1000 Experience PointsRecommendation Second Class
    Charly tiene un aura espectacular Charly tiene un aura espectacular Charly tiene un aura espectacular Avatar de Charly
    Fecha de Ingreso
    Apr 2008
    Ubicación
    tigre. Bs.As Arg
    Edad
    33
    Mensajes
    1,362
    Puntos
    7,271
    Nivel
    56
    Gracias
    9
    Agradecido 1 Time in 1 Post

    Predeterminado (tutorial) ensamblador y programacion

    Tutorial Ensamblador

    Parte 3: Manejo del Emulador

    Si usted quiere cargar su código compilado en el emulador, haga clic sobre el botón "Emulate" .
    También puede usar el emulador para cargar ficheros ejecutables incluso aunque usted no tenga el código fuente original en lenguaje ensamblador. Seleccione "Show Emulator" del menu "Emulator".



    Intente cargar algún fichero de la carpeta "MyBuild". Si no hubiese ningún fichero en dicha carpeta regrese al editor de código fuente, y seleccione Samples en el menú File, abra cualquier ejemplo, compÃÂ*lelo y después cárguelo en el emulador:



    [Single Step] Este botón ejecuta las instrucciones una a una parando después de cada instrucción.

    [Run] Este botón ejecuta las instrucciones secuencialmente sin interrupciones con un retraso (delay) entre instrucción e instrucción que se puede ajustar por medio de la barra deslizadora step delay (parte superior derecha de la ventana).

    Realizar doble clic en los text-boxes correspondientes a los registros abre la ventana "Extended Viewer" con el valor de dicho registro convertido a todos los formatos posibles. Podrá pues modificar el valor del registro directamente en esta ventana.

    Realizar doble clic en un ÃÂ*tem del listado de memoria (memory list) abre la ventana "Extended Viewer" con un valor de tipo WORD cargado desde la localización de memoria seleccionada del citado listado. El byte menos significativo (LOW BYTE) esta en la dirección mas baja y se corresponde con la dirección seleccionada; por tanto el byte mas significativo (HIGH BYTE) se carga de la siguiente dirección de memoria. Podrá modificar pues este WORD seleccionado modificando directamente sus valores en la ventana "Extended Viewer".

    También puede modificar los valores de los registros en tiempo de ejecución escribiendo directamente sobre los valores existentes.

    [Flags] Este botón le permitirá ver y modificar las banderas en tiempo de ejecución (runtime).

    Discos Virtuales (Virtual Drives)


    EL Emulador soporta hasta 4 discos floppy virtuales (virtual floppy drives). Por defecto hay un fichero llamado FLOPPY_0 que es una imagen de un disquete real (el tamaño del fichero es exactamente 1,474,560 bytes).

    Para añadir mas disquetes (floppy drives) seleccione [Create new floppy drive] en el menú [Virtual Drive]. Cada vez que añada un disco el emulador creara un fichero llamado FLOPPY_1, FLOPPY_2, y FLOPPY_3.
    Los disquetes son imagines de disquetes formateados estilo IBM/MS-DOS vacÃÂ*os. Recuerde que solo puede llegar hasta 4 discos.
    Para borrar un floppy deberá cerrar el emulador, y borrar manualmente el fichero deseado y reiniciar el emulador.

    Podrá determinar el número de discos empleados utilizando la interrupción INT 11h, esta devolverá en el registro AX una lista con el equipamiento que detecte la BIOS. Los Bits 7 y 6 definen el número de discos creados menos 1, ya que se empiezan a numerar desde cero:

    Bits 7-6 de AX:

    00 1 floppy disk.

    01 2 floppy disks.

    10 3 floppy disks.

    11 4 floppy disks.

    El Emulador empieza a contar los discos utilizados empezando por el primero, y caso de que no exista va al siguiente, en este caso el fichero FLOPPY_1. Si este no existe no se molesta en buscar los ficheros correspondientes a FLOPPY_2 y FLOPPY_3.

    Para leer y escribir información de un floppy podremos utilizar la interrupción INT 13h, mas adelante veremos una lista completa de las interrupciones que soporta el micro.

    ¿Ha deseado escribir alguna vez su propio sistema operativo?

    Podrá manipular el sector de arranque (boot sector) de un disquete virtual a través del siguiente menu:

    [Virtual Drive] -> [Write 512 bytes at 7C00 to Boot Sector]
    Primero deberá compilar un fichero de tipo ".boot" y cargarlo en el emulador (vea el ejemplo "micro-os_loader.asm" y "micro-os_kernel.asm" en la carpeta "Samples" para mayor información).

    Seleccione después la opción [Virtual Drive] -> [Boot from Floppy] de menú para arrancar el emulador desde un disquete virtual.

    Si además esta interesado en el tema, podrá copiar el disco virtual en un disquete real y arrancar su equipo con el. Se aconseja emplear el método "RawWrite for Windows" explicado en el siguiente enlace: Solo los usuarios registrados pueden ver los links. Registrarse aquí
    (fijese que en ejemplo "micro-os_loader.asm" no se usa un sector de arranque compatible con MS-DOS, luego es mejor utilizar un disco totalmente vacÃÂ*o, aunque este formateado en modo IBM (MS-DOS).

    La directiva de compilación ORG 7C00h deberá ser añadida antes del código, para que cuando el ordenador arranque cargue la primera pista (track) del floppy en la dirección de memoria 0000:7C00.
    El tamaño del fichero .BOOT deberá ser menor que 512 bytes (que es el limite del tamaño de un sector de floppy).

    El comentar no Produce ninguna enfermedad infectocontagiosa,
    valora el esfuerso de los que postean y comenta!!!
    gracias


  4. #4
    Administrator
    Puntos: 7,271, Nivel: 56
    Nivel completado: 61%, Puntos necesarios para el proximo Nivel: 79
    Actividad total: 10.1%
    Logros:
    100 Experience Points250 Experience Points500 Experience Points1000 Experience PointsRecommendation Second Class
    Charly tiene un aura espectacular Charly tiene un aura espectacular Charly tiene un aura espectacular Avatar de Charly
    Fecha de Ingreso
    Apr 2008
    Ubicación
    tigre. Bs.As Arg
    Edad
    33
    Mensajes
    1,362
    Puntos
    7,271
    Nivel
    56
    Gracias
    9
    Agradecido 1 Time in 1 Post

    Predeterminado Re: como crear un s.o (tutorial)

    Tutorial Ensamblador

    Parte 4: Acceso a Memoria

    Para acceder a la memoria podemos usar los siguientes cuatro registros: BX, SI, DI, BP.
    Combinando dichos registros dentro del sÃÂ*mbolo [ ], podemos acceder a diferentes localizaciones de memoria. Las siguientes combinaciones son admitidas (modos de direccionamiento):


    [BX + SI] [SI] [BX + SI] + d8
    [BX + DI] [DI] [BX + DI] + d8
    [BP + SI] d16 (solo offset de la variable) [BP + SI] + d8
    [BP + DI] [BX] [BP + DI] + d8

    [SI] + d8 [BX + SI] + d16 [SI] + d16
    [DI] + d8 [BX + DI] + d16 [DI] + d16
    [BP] + d8 [BP + SI] + d16 [BP] + d16
    [BX] + d8 [BP + DI] + d16 [BX] + d16

    d8 - significa offset de 8 bits.

    d16 - significa offset 16 bits.


    El Offset o Desplazamiento puede ser un dato (immediate value) o el offset de una variable, o incluso ambas cosas. Será el compilador el encargado de calcular el valor correspondiente para direccionar.

    El Offset puede estar dentro o fuera de los sÃÂ*mbolos [ ], el compilador genera el mismo código maquina de ambas maneras.

    El Desplazamiento es un valor con signo (signed), luego puede ser positivo o negativo.

    Generalmente el compilador se preocupa de la diferencia entre los offsets de 8 y 16 bits (d8 y d16), y genera el código maquina adecuado.

    Por ejemplo, supongamos que DS = 100, BX = 30, SI = 70.

    Y el siguiente modo de direccionamiento: [BX + SI] + 25 es convertido por el procesador a la siguiente dirección fÃÂ*sica: 100 * 16 + 30 + 70 + 25 = 1725.

    Por defecto el registro de segmento DS es usado por todos los métodos excepto aquellos que usan el registro BP, que se usa en combinación con el registro de segmento SS.

    Hay una regla fácil para recordar todas las combinaciones posibles según el siguiente grafico usando el siguiente grafico:



    Podrás formar tantas combinaciones validas tomando un elemento de cada columna o saltándote alguna de ellas. Como ves BX y BP nunca van juntos. Del mismo modo SI y DI tampoco. Veamos un ejemplo de direccionamiento valido: [BX+5].

    El valor de un registro de segmento (CS, DS, SS, ES) es llamado "segmento o base", y el valor de un registro de propósito general (BX, SI, DI, BP) es llamado el "offset".

    Cuando DS contiene el valor 1234h y SI contiene el valor 7890h tendremos la dirección de memoria 1234:7890. La verdadera dirección fÃÂ*sica será haciendo cuentas 1234h * 10h + 7890h = 19BD0h.

    Para avisar al compilador acerca de los tipos de datos empleados usaremos los siguientes prefijos:

    BYTE PTR – para un byte.
    WORD PTR - para un word (dos bytes).

    Por ejemplo:

    BYTE PTR [BX] (acceso a un byte de memoria) o WORD PTR [BX] (acceso a un word de memoria).

    Emu8086 soporta los prefijos cortos también:

    b. - para BYTE PTR
    w. - para WORD PTR

    En algunas ocasiones el compilador podrá calcular de forma automática el tipo de dato, pero mejor que no confÃÂ*es en ello cuando uno de los operandos es un dato (immediate value).

    Instrucción MOV

    · Copia el segundo operando (source) en el primer operando (destination).

    · El operando source puede ser un dato, un registro de propósito general o una posición de memoria (variable).

    · El operando destination puede ser un registro de propósito general o una posición de memoria (variable).

    · Ambos operandos deben ser del mismo tamaño, es decir o un byte o un word.

    Se admiten los siguientes tipos de operandos:

    * MOV REG, memoria
    MOV memoria, REG
    MOV REG, REG
    MOV memoria, dato
    MOV REG, dato
    * REG: AX, BX, CX, DX, AH, AL, BL, BH, CH, CL, DH, DL, DI, SI, BP, SP.

    memoria: [BX], [BX+SI+7], variable, etc.

    dato: 5, -24, 3Fh, 10001101b, etc.

    Para registros de segmento solo se admiten los siguientes operandos:

    * MOV SREG, memoria
    MOV memoria, SREG
    MOV REG, SREG
    MOV SREG, REG
    * SREG: DS, ES, SS, y solo como segundo operando: CS.

    REG: AX, BX, CX, DX, AH, AL, BL, BH, CH, CL, DH, DL, DI, SI, BP, SP.

    memoria: [BX], [BX+SI+7], variable, etc.


    La instrucción MOV no puede ser usada para ajustar el valor de los registros CS e IP.

    Ejemplo de programa corto que demuestra el uso de la instrucción MOV:



    #MAKE_COM#

    ORG 100h

    MOV AX, 0B800h ; ajusta AX a B800h.

    MOV DS, AX ; copia el valor de AX en DS.

    MOV CL, 'A' ; ajusta CL al código ASCII de 'A', es 41h.

    MOV CH, 01011111b; ajusta CH a un valor binario.

    MOV BX, 15Eh ; ajusta BX a 15Eh.

    MOV [BX], CX ; copia los contenidos del registro CX a la dirección de memoria B800:015E

    RET

    Pruébelo en su emulador, utilizando la opción [Single Step] para observar los valores de los registros.

    Los comentarios emplean el sÃÂ*mbolo ";" antes de ser escritos. Este sÃÂ*mbolo es ignorado al compilarse.

    DeberÃÂ*as ver algo parecido en la pantalla de usuario cuando el programa finaliza:



    Actualmente el programa escribe directamente a la memoria de video, note que la instruccion MOV es muy potente.

    El comentar no Produce ninguna enfermedad infectocontagiosa,
    valora el esfuerso de los que postean y comenta!!!
    gracias


  5. #5
    Administrator
    Puntos: 7,271, Nivel: 56
    Nivel completado: 61%, Puntos necesarios para el proximo Nivel: 79
    Actividad total: 10.1%
    Logros:
    100 Experience Points250 Experience Points500 Experience Points1000 Experience PointsRecommendation Second Class
    Charly tiene un aura espectacular Charly tiene un aura espectacular Charly tiene un aura espectacular Avatar de Charly
    Fecha de Ingreso
    Apr 2008
    Ubicación
    tigre. Bs.As Arg
    Edad
    33
    Mensajes
    1,362
    Puntos
    7,271
    Nivel
    56
    Gracias
    9
    Agradecido 1 Time in 1 Post

    Predeterminado Re: como crear un s.o (tutorial)

    Tutorial Ensamblador

    Parte 5: Variables

    Una Variable es una posición de memoria. Para un programador es más fácil guardar un valor en la variable llamada "var1" que decir que esta en la posición (dirección) de memoria 5A73:235B, especialmente cuando manejamos más de 10 variables.

    El compilador admite dos tipos de variables: BYTE y WORD.


    Sintaxis para la declaración de una variable:

    nombre DB valor

    nombre DW valor

    DB - significa Define Byte.
    DW - significa Define Word.

    Nombre – puede ser cualquier combinación de letras o dÃÂ*gitos, empezando por un carácter. Es posible declarar variables sin especificar un nombre (esta variable tendrá una dirección pero no un nombre).

    Valor – puede ser cualquier valor numérico en cualquier sistema de numeración soportado (hexadecimal, binario, octal o decimal), o el sÃÂ*mbolo "?" para variables que no están inicializadas.

    Veamos un nuevo ejemplo de uso de la instrucción MOV:

    #MAKE_COM#
    ORG 100h
    MOV AL, var1
    MOV BX, var2
    RET ; para el programa.
    VAR1 DB 7
    var2 DW 1234h
    END

    Si copiamos el codigo anterior en el emulador y compilamos tendremos la siguiente ventana:



    Como vemos se parece bastante a nuestro ejemplo, excepto que las variables han sido reemplazadas por sus direcciones actuales de memoria (memory locations). Cuando el compilador crea código maquina, automáticamente reemplaza todos los nombres de variables por sus offsets. Por defecto la base de la dirección se carga en el registro de segmento de datos DS (por ejemplo en los ficheros COM se carga el valor del registro DS con el mismo valor que el registro de segmento de código CS).

    En la lista de memoria la primera columna es un offset, la segunda es un valor hexadecimal, la tercera es un valor decimal, y la última columna es el valor correspondiente del carácter ASCII.

    El Compilador no distingue mayúsculas de minúsculas, luego "VAR1" y "var1" son la misma variable.

    El offset de VAR1 es 0108h, y su dirección completa es 0B56:0108.

    El offset de var2 es 0109h, y su dirección completa es 0B56:0109, esta variable es un WORD luego ocupa 2 BYTES.

    Se asume que el byte bajo (low) se almacena en la dirección más alta, luego 34h esta localizado antes que 12h.

    Podemos ver que hay alguna instrucción más después de RET instrucción, se debe a que el código desensamblado no tiene idea de donde comienzan los datos, y procesa los valores en memoria como si fueran instrucciones validas del ensamblador

    El mismo programa usando solo DB:

    #MAKE_COM#

    ORG 100h



    DB 0A0h

    DB 08h

    DB 01h



    DB 8Bh

    DB 1Eh

    DB 09h

    DB 01h



    DB 0C3h



    DB 7



    DB 34h

    DB 12h


    El compilador solo convierte el código fuente (program source) a un conjunto de bytes, denominados código maquina (machine code). El micro entiende el código máquina y lo ejecuta.

    ORG 100h es una directiva de compilación (que informa al compilador de como manipular el código fuente). Es muy importante a la hora de trabajar con variables. El compilador sabe que el código ejecutable estará cargado en el offset 100h (256 bytes), con lo que el compilador recalculara la dirección correcta para todas las variables cuando reemplace los nombres de las variables con sus correspondientes offsets. Las Directivas nunca se convierten en codigo maquina real.

    ¿Por que un fichero ejecutable es cargado en el offset 100h? El sistema Operativo guarda datos sobre el programa en los primeros 256 bytes del segmento de código CS, como parámetros para la lÃÂ*nea de ordenes.


    Aunque esto es cierto para los ficheros COM solo, ya que los de tipo EXE se cargan con un offset de valor 0000h, y usan segmentos especiales para las variables.

    Arrays (Vectores)

    Podemos interpretar un array como una cadena de variables. Una cadena de texto es un ejemplo de un array de tipo byte, donde cada carácter es presentado con su valor de código ASCII (de 0 a 255).

    Ejemplos de definición de arrays:

    a DB 48h, 65h, 6Ch, 6Ch, 6Fh, 00h

    b DB 'Hola', 0

    b es una copia exacta del array a, cuando el compilador ve una cadena dentro de apostrofes la convierte automaticamente en un conjunto de bytes. Este grafico muestra una parte de la memoria cuando se declaran esta tipo de arrays:



    Podemos tener acceso al valor de cualquier elemento del array usando corchetes:

    MOV AL, a[3]

    Podemos también utilizar como posicionador cualquiera de los registros siguientes: BX, SI, DI, BP, por ejemplo:

    MOV SI, 3

    MOV AL, a[SI]

    Si vamos a declarar un array muy largo podemos usar el operador DUP.

    La sintaxis para DUP es:

    numero DUP ( valor(es) )

    numero - numero de duplicaciones a realizar (un valor constante).

    valor - expresión que el operador DUP replicara.



    Por ejemplo:

    c DB 5 DUP(9)

    es la alternativa para declarar:

    c DB 9, 9, 9, 9, 9



    Otro ejemplo:

    d DB 5 DUP(1, 2)

    es la alternativa para declarar:

    d DB 1, 2, 1, 2, 1, 2, 1, 2, 1, 2

    Por supuesto, podemos usar DW en vez de DB si es necesario almacenar valores superiores a 255, o menores que -128. ¡DW NO PUEDE SER UTILIZADO PARA DECLARAR STRINGS!

    La expansión provocada por DUP no puede superar 1020 caracteres. La expansión del ultimo ejemplo es 13 caracteres, si necesitásemos declarar un amplio array dividiremos la declaración en dos lÃÂ*neas (aunque tendremos un solo array reservado en la memoria).

    Obtener la Dirección de Memoria de una Variable

    Hay una instrucción LEA (Load Effective Address), que carga la dirección efectiva y un operador alternativo denominado OFFSET. Ambos OFFSET y LEA pueden ser usados para obtener el offset de la dirección de memoria donde esta ubicada una variable.

    LEA es mas potente porque también permite obtener las direcciones de variables que utilizan ÃÂ*ndices. Obtener la dirección de una variable puede ser muy útil en algunas situaciones, por ejemplo cuando necesitamos PASAR PARAMETROS A UN PROCEDIMIENTO.


    NOTA:
    Para advertir al compilador de tipo de dato utilizaremos los prefijos:

    BYTE PTR - byte.

    WORD PTR - word (dos bytes).

    Por ejemplo:

    BYTE PTR [BX]; acceso a un byte. WORD PTR [BX]; acceso a un word.



    También podemos emplear prefijos cortos:

    b. - para BYTE PTR

    w. - para WORD PTR

    Algunas veces el compilador puede detectar automáticamente el tipo de dato al que se quiere acceder, aunque no te fÃÂ*es demasiado sobre todo si uno de los operandos es un dato (immediate value).



    Un primer ejemplo:

    ORG 100h

    MOV AL, VAR1 ; chequea el valor de VAR1 moviéndolo a AL.

    LEA BX, VAR1 ; obtiene la dirección de VAR1 en BX.

    MOV BYTE PTR [BX], 44h ; modifica los contenidos de VAR1.

    MOV AL, VAR1 ; chequea el valor de VAR1 moviéndolo a AL.

    RET

    VAR1 DB 22h

    END




    Un segundo ejemplo, usando OFFSET en vez de LEA:

    ORG 100h

    MOV AL, VAR1 ; chequea el valor de VAR1 moviéndolo a AL.

    MOV BX, OFFSET VAR1 ; obtiene la dirección de VAR1 en BX.

    MOV BYTE PTR [BX], 44h ; modifica los contenidos de VAR1.

    MOV AL, VAR1 ; chequea el valor de VAR1 moviéndolo a AL.

    RET

    VAR1 DB 22h

    END


    Ambos ejemplos tienen la misma funcionalidad.

    Las lÃÂ*neas:
    LEA BX, VAR1
    MOV BX, OFFSET VAR1
    son compiladas provocando el mismo código maquina: MOV BX, num
    num es un valor de 16 bits con el offset de la variable.

    NOTA: solo estos registros pueden ser usados entre corchetes (como punteros de memoria): BX, SI, DI, BP.



    Constantes

    Las Constantes son parecidas a las variables, pero solo existen cuando el programa es compilado (ensamblado). Después de la definición de una constante su valor no puede ser cambiado. Para definir constantes se usa la directiva EQU:

    nombre EQU <cualquier expresión>

    Por ejemplo:

    k EQU 5

    MOV AX, k
    Que en funcionalidad es idéntico al siguiente código:
    MOV AX, 5

    Podemos observar las variables mientras se ejecuta nuestro programa seleccionando "Variables" en el menú "View" del emulador.



    Para ver arrays hacemos clic en una variable y ajustamos el número de elementos visibles. En lenguaje ensamblador no hay tipos de datos estrictos, luego cualquier variable puede ser presentada como un array.

    Las Variables pueden ser vistas en cualquier sistema de numeración:

    HEX - hexadecimal (base 16).

    BIN - binario (base 2).

    OCT - octal (base 8).

    SIGNED – decimal con signo (base 10).

    UNSIGNED – decimal sin signo (base 10).

    CHAR – código de caracteres ASCII (hay 256 sÃÂ*mbolos, algunos no visibles).

    Podremos editar el valor de una variable aunque el programa se este ejecutando, haciendo doble clic sobre el nombre de la variable, o seleccionándola y editándola.

    Es posible introducir números en cualquier sistema, hexadecimal con sufijo "h", binario con sufijo "b", octal con sufijo "o", y decimal que no requiere sufijo. Las cadenas de caracteres (String) se introducirán de la siguiente forma:
    'hola mundo', 0 (siempre serán strings cero-terminadas).

    Los Arrays se introducen de la siguiente manera:
    1, 2, 3, 4, 5 (el array puede ser de bytes o words, depende si seleccionamos BYTE o WORD para la variable a editar).


    Las Expresiones son automáticamente evaluadas, por ejemplo:
    5 + 2 es automáticamente convertido en 7 etc.

    El comentar no Produce ninguna enfermedad infectocontagiosa,
    valora el esfuerso de los que postean y comenta!!!
    gracias


  6. #6
    Administrator
    Puntos: 7,271, Nivel: 56
    Nivel completado: 61%, Puntos necesarios para el proximo Nivel: 79
    Actividad total: 10.1%
    Logros:
    100 Experience Points250 Experience Points500 Experience Points1000 Experience PointsRecommendation Second Class
    Charly tiene un aura espectacular Charly tiene un aura espectacular Charly tiene un aura espectacular Avatar de Charly
    Fecha de Ingreso
    Apr 2008
    Ubicación
    tigre. Bs.As Arg
    Edad
    33
    Mensajes
    1,362
    Puntos
    7,271
    Nivel
    56
    Gracias
    9
    Agradecido 1 Time in 1 Post

    Predeterminado Re: como crear un s.o (tutorial)

    Tutorial Ensamblador

    Parte 6: Interrupciones

    Podemos interpretar las Interrupciones como un conjunto de funciones, que hacen que la programación sea más fácil. En vez de escribir el código necesario para imprimir un carácter en pantalla simplemente llamaremos a una interrupción y realizara todo el proceso por nosotros. Hay también interrupciones que trabajan con el disco duro y con otro hardware. A estas funciones las denominamos interrupciones por software.


    Las interrupciones también pueden se provocadas por diferentes dispositivos de hardware, denominadas interrupciones por hardware. Solo nos preocuparemos de las interrupciones por software.


    Para realizar una interrupción por software emplearemos la instrucción INT, cuya sintaxis es muy simple:

    INT valor

    Donde valor es un numero entere 0 y 255 (0h hasta 0FFh), generalmente usaremos números hexadecimales.

    PodrÃÂ*amos pensar que solo hay 256 interrupciones posibles, pero no es correcto ya que cada interrupción puede tener sub-funciones. Para especificar una sub-función se emplea el registro AH antes de la llamada a la interrupción.
    Cada interrupción puede tener hasta 256 sub-funciones (por lo tanto tendremos hasta 256 * 256 = 65536 interrupciones diferentes). En general se utiliza el registro AH, pero en ocasiones también se utilizan otros registros. Generalmente para pasar parámetros y datos a la sub-función.

    El siguiente ejemplo utiliza la interrupción INT 10h con sub-función 0Eh para escribir el mensaje "Hola". Esta interrupción muestra un carácter en pantalla, haciendo que el cursor avance una posición y haciendo scrolling de la pantalla si fuese necesario.

    #MAKE_COM#

    ORG 100h

    ; La sub-funcion que estamos usando

    ; no modifica el registro AH , solo deberemos

    ; ajustarlo una vez al principio.

    MOV AH, 0Eh ; selecciona una sub-función.

    ; INT 10h / 0Eh sacará a pantalla el ASCII

    ; del carácter situado en el registro AL.



    MOV AL, 'H'

    INT 10h ; lo imprime.

    MOV AL, 'o'

    INT 10h ; lo imprime.

    MOV AL, 'l'

    INT 10h ; lo imprime.

    MOV AL, 'a'

    INT 10h ; print it!

    RET ; regresa al S.O. (operating system).

    Emula el anterior código paso a paso en el Emu8086.

    Existe un documento con la lista de interrupciones soportadas lista de interrupciones soportadas para mas información acerca de las diferentes interrupciones y sub-funciones.

    El comentar no Produce ninguna enfermedad infectocontagiosa,
    valora el esfuerso de los que postean y comenta!!!
    gracias


  7. #7
    Administrator
    Puntos: 7,271, Nivel: 56
    Nivel completado: 61%, Puntos necesarios para el proximo Nivel: 79
    Actividad total: 10.1%
    Logros:
    100 Experience Points250 Experience Points500 Experience Points1000 Experience PointsRecommendation Second Class
    Charly tiene un aura espectacular Charly tiene un aura espectacular Charly tiene un aura espectacular Avatar de Charly
    Fecha de Ingreso
    Apr 2008
    Ubicación
    tigre. Bs.As Arg
    Edad
    33
    Mensajes
    1,362
    Puntos
    7,271
    Nivel
    56
    Gracias
    9
    Agradecido 1 Time in 1 Post

    Predeterminado Re: como crear un s.o (tutorial)

    Tutorial Ensamblador

    Parte 7: Biblioteca de Funciones

    Para que la programación sea más sencilla hay algunas funciones comunes que podemos utilizar en nuestro código. Podemos incluir en nuestro programa funciones definidas en otro fichero que referenciamos usando la directiva INCLUDE seguida del nombre del fichero. El Compilador automáticamente busca el fichero en la misma carpeta donde hemos salvado nuestro programa, y caso de no encontrarlo lo busca en la carpeta Inc donde esta instalado el emulador.


    Probablemente en este momento no seamos todavÃÂ*a capaces de entender por completo los contenidos del fichero emu8086.inc (localizado en la carpeta Inc), pero nos vale que comprendamos básicamente el funcionamiento de las funciones que incluye.


    Para usar cualquiera de las funciones del fichero emu8086.inc debemos incluir la siguiente lÃÂ*nea de código en nuestro programa:


    include 'emu8086.inc'




    En emu8086.inc están definidas las siguientes MACROS:



    · PUTC char - macro con 1 parámetro, imprime un carácter ASCII en la posición actual del cursor.



    · GOTOXY col, row - macro con 2 parámetros, ajusta la posición del cursor.



    · PRINT string - macro con 1 parámetro, imprime una cadena (string).



    · PRINTN string - macro con 1 parámetro, imprime una cadena (string), pero automáticamente añade un retorno de carro (carriage return) al final de la cadena.



    · CURSOROFF – desaparece el cursor de texto.



    · CURSORON - aparece el cursor de texto.



    Para utilizar cualquiera de las macros citadas simplemente tecleamos su nombre donde corresponda en nuestro código incluyendo los parámetros necesarios, por ejemplo:



    include emu8086.inc



    ORG 100h



    PRINT 'Hola Mundo!'



    GOTOXY 10,5



    PUTC 65 ; 65 – código ASCII de 'A'

    PUTC 'B'



    RET ; vuelve al sistema operativo.

    END ; directiva que para el compilador.



    Cuando el compilador procesa tu código fuente (source) busca en el fichero emu8086.inc las declaraciones de las macros y REEMPLAZA EL NOMBRE DE LA MACRO POR SU CODIGO REAL (el de la librerÃÂ*a). Generalmente las macros son partes relativamente pequeñas de código, pero ojo porque el uso frecuente de una macro puede generar un fichero ejecutable MUY LARGO. Los procedimientos son mejores para optimizar el tamaño final de fichero.




    En emu8086.inc están las definiciones de los siguientes PROCEDIMIENTOS:



    PRINT_STRING – procedimiento para imprimir una cadena cero (null)-terminada en la posición actual del cursor, la dirección efectiva de la cadena se gorma con la combinación de registros DS:SI. Para utilizar el procedimiento debemos declararlo como DEFINE_PRINT_STRING antes de la directiva END.



    PTHIS - procedimiento para imprimir una cadena cero (null)-terminada en la posición actual del cursor (lo mismo que PRINT_STRING), pero toma la dirección efectiva de la Pila de Memoria (Stack). La cadena cero (null)-terminada debe ser definida justo después de la instrucción de llamada al procedimiento (instrucción CALL). Por ejemplo:

    CALL PTHIS db 'Hola Mundo',0


    Para utilizar el procedimiento debemos declararlo como DEFINE_PTHIS antes de la directiva END.



    GET_STRING - procedimiento para obtener una cadena cero (null)-terminada del usuario, la cadena obtenida es escrita desde el buffer a la dirección de memoria efectiva DS:DI, y el tamaño del buffer debe estar ajustado en el registro DX. El procedimiento detiene la entrada de caracteres cuando se presiona la tecla 'Enter'. Para utilizar el procedimiento debemos declararlo como DEFINE_GET_STRING antes de la directiva END.



    CLEAR_SCREEN – Procedimiento que limpia la pantalla, (mediante la realización de un scrolling a toda la ventana de la pantalla), y ajustando la posición del cursor en la parte superior de la pantalla. Para utilizar el procedimiento debemos declararlo como DEFINE_CLEAR_STRING antes de la directiva END.



    SCAN_NUM – Procedimiento que obtiene un número con signo (SIGNED) de varios dÃÂ*gitos procedente del teclado y lo almacena en el registro CX cuando se pulsa la tecla 'Enter'. Para utilizar el procedimiento debemos declararlo como DEFINE_SCAN_NUM antes de la directiva END.



    PRINT_NUM – Procedimiento que imprime un número con signo desde el registro AX. Para utilizar el procedimiento debemos declararlo como DEFINE_PRINT_NUM conjuntamente con DEFINE_PRINT_NUM_UNS antes de la directiva END.



    PRINT_NUM_UNS - Procedimiento que imprime un número sin signo (UNSIGNED) desde el registro AX. Para utilizar el procedimiento debemos declararlo como DEFINE_PRINT_NUM_UNS antes de la directiva END.


    Para usar cualquiera de los procedimientos vistos primero debemos declararlos al final del código, pero antes de la directiva END y después usar la instrucción CALL seguida del nombre del procedimiento cuando deseemos utilizarlo en nuestro código. Por ejemplo:



    include 'emu8086.inc'



    ORG 100h



    LEA SI, msj1 ; pide un numero

    CALL print_string

    CALL scan_num ; guarda el numero en CX.



    MOV AX, CX ; copia el numero en AX.



    ; imprime la siguiente cadena:

    CALL pthis

    DB 13, 10, 'Has introducido el numero: ',0



    CALL print_num ; imprime el numero desde AX.



    RET ; regresa al sistema operativo.



    msj1 DB 'Introduzca un numero: ',0



    DEFINE_SCAN_NUM

    DEFINE_PRINT_STRING

    DEFINE_PRINT_NUM

    DEFINE_PRINT_NUM_UNS ; requerido por print_num.

    DEFINE_PTHIS



    END ; directiva que para el compilador.

    Primero el compilador procesa las declaraciones cargando los procedimientos en alguna zona libre de la memoria. Cuando el compilador procesa la instrucción CALL reemplaza el nombre del procedimiento con la dirección efectiva de memoria donde se ha cargado el código del procedimiento cuando fue declarado. Cuando se ejecuta la instrucción CALL se transfiere el control desde el programa principal al código del procedimiento, que se ejecuta y cuando finaliza devuelve de nuevo el control al programa principal que lo llamó. Es muy útil ya que aunque llamemos 100 veces al mismo procedimiento no estaremos generando mas código y nuestros ejecutables serán de tamaño razonable.

    El comentar no Produce ninguna enfermedad infectocontagiosa,
    valora el esfuerso de los que postean y comenta!!!
    gracias


  8. #8
    Administrator
    Puntos: 7,271, Nivel: 56
    Nivel completado: 61%, Puntos necesarios para el proximo Nivel: 79
    Actividad total: 10.1%
    Logros:
    100 Experience Points250 Experience Points500 Experience Points1000 Experience PointsRecommendation Second Class
    Charly tiene un aura espectacular Charly tiene un aura espectacular Charly tiene un aura espectacular Avatar de Charly
    Fecha de Ingreso
    Apr 2008
    Ubicación
    tigre. Bs.As Arg
    Edad
    33
    Mensajes
    1,362
    Puntos
    7,271
    Nivel
    56
    Gracias
    9
    Agradecido 1 Time in 1 Post

    Predeterminado (tutorial) ensamblador y programacion

    8. Instrucciones Aritmeticas y Logicas

    La mayoria de las instrucciones Aritmeticas y Logicas afectan al estado de las banderas del procesador (Flags)



    En el registro de flags hay 16 bits, cada bit es llamado bandera o flag y toma los valores 1 o 0.

    * Carry Flag (CF) - esta flag sube a 1 cuando hay un overflow sin signo. Por ejemplo cuando sumas 255 + 1 (resultado fuera del rango 0 a 255). Si no hay overflow la bandera esta a 0.

    * Zero Flag (ZF) – sube a 1 cuando un resultado es cero. De lo contrario esta a 0.

    * Sign Flag (SF) – sube a 1 cuando el resultado es negativo. Si es positivo esta a 0. O sea toma el valor del bit mas significativo cuando trabajamos con signo.
    * Overflow Flag (OF) - sube a 1 cuando hay overflow con signo. Por ejemplo, si sumas 100 + 50 (el resultado no esta en el rango de -128 a 127).

    * Parity Flag (PF) – sube a 1 cuando hay un numero par de bits que toman el valor uno en el resultado, y queda a 0 cuando dicho numero es par. Aunque el resultado de un word solo se analizan los 8 bits menos significativos.

    * Auxiliary Flag (AF) – sube a 1 cuando hay un overflow sin signo para el nibble (4 bits) mas bajo.

    * Interrupt enable Flag (IF) – si esta a 1 la CPU atiende las interrupciones de dispositivos externos.
    * Direction Flag (DF) – es usada por algunas instrucciones para procesar cadenas de datos, si esta a 0 – la direccion es natural, si esta a 1 la direccion es hacia atras.

    Hay 3 grupos de instrucciones.
    Primer grupo: ADD, SUB,CMP, AND, TEST, OR, XOR
    Que manejan los siguientes operandos:
    REG, memory
    memory, REG
    REG, REG
    memory, immediate
    REG, immediate
    REG: AX, BX, CX, DX, AH, AL, BL, BH, CH, CL, DH, DL, DI, SI, BP, SP.
    memoria: [BX], [BX+SI+7], variables, etc...
    datos (immediates): 5, -24, 3Fh, 10001101b, etc...

    Después de la operacion entre los operandos, el resultado es siempre almacenado en el primer operando. CMP y TEST son instrucciones que afectan solo a flags y no almacenan ningun resultado (son instrucciones usadas para tomar decisiones durante la ejecución de un programa).
    Las banderas o flags afectados por estas instrucciones son:

    CF, ZF, SF, OF, PF, AF.
    * ADD – suma 2º operando al 1º.
    * SUB - resta 2º operando al 1º.
    * CMP – RESTA LOS OPERANDOS SEGUNDO Y PRIMERO afectando solo a las flags.
    * AND – Operacion Y (AND) Logica entre cada bit de los dos operandos. Se aplica la regla:
    1 AND 1 = 1
    1 AND 0 = 0
    0 AND 1 = 0
    0 AND 0 = 0

    Solo obtenemos 1 si ambos bits son 1.

    * TEST – Lo mismo que AND pero SOLO AFECTA A LAS FLAGS, SIN RESULTADO ALMACENADO.
    * OR – Operacion O (OR) Logica entre cada bit de los dos operandos. Se aplica la regla:
    1 OR 1 = 1
    1 OR 0 = 1
    0 OR 1 = 1
    0 OR 0 = 0

    Siempre tenemos 1 si al menos hay un 1 en alguno de los bits.
    * XOR - Operacion XOR (O-exclusiva) entre cada bit de los dos operandos. Se aplica la regla:
    1 XOR 1 = 0
    1 XOR 0 = 1
    0 XOR 1 = 1
    0 XOR 0 = 0

    Tendremos un 1 siempre que los valores de los bits sean diferentes entre si.
    Segundo grupo: MUL, IMUL, DIV, IDIV
    Que manejan los siguientes operandos:

    REG

    memory
    REG: AX, BX, CX, DX, AH, AL, BL, BH, CH, CL, DH, DL, DI, SI, BP, SP.
    memoria: [BX], [BX+SI+7], variables, etc...
    MUL e IMUL son instrucciones que afectan a las siguientes flags:
    CF, OF
    Si el resultado supera el tamño del operando estas flags suben a 1, si el resultado cabe en el operando quedan a 0.

    Para DIV e IDIV las flags quedan indefinidas (no son utiles).

    * MUL – Multiplicación sin signo:
    Si el operando es 1 byte:
    AX = AL * operando.
    Si el operando es 1 word:
    (DX AX) = AX * operando.
    * IMUL – Multiplicación con signo:
    Si el operando es 1 byte:
    AX = AL * operando.
    Si el operando es 1 word:
    (DX AX) = AX * operando.
    * DIV – Division sin signo:
    Si el operando es 1 byte:
    AL = AX / operando
    AH = resto o remainder (modulus). .
    Si el operando es 1 word:
    AX = (DX AX) / operando
    DX = resto o remainder (modulus). .
    * IDIV – Division con signo:
    Si el operando es 1 byte:
    AL = AX / operando
    AH = resto o remainder (modulus). .
    Si el operando es 1 word:
    AX = (DX AX) / operando
    DX = resto o remainder (modulus). .
    Tercer grupo: INC, DEC, NOT, NEG
    Que manejan los siguientes operandos:

    REG
    memory
    REG: AX, BX, CX, DX, AH, AL, BL, BH, CH, CL, DH, DL, DI, SI, BP, SP.
    memoria: [BX], [BX+SI+7], variables, etc...
    INC, DEC son instruccione que afectan solo a las flags:
    ZF, SF, OF, PF, AF.

    NOT es una instruccion que NO modifica ninguna flag
    NEG es una instruccion que afecta a las flags:
    CF, ZF, SF, OF, PF, AF.

    * NOT – Invierte cada bit del operando
    * NEG – Hace negativo al operando (complemento a 2). Realmente invierte cada bit del operando Y LUEGO LE AÑADE 1. Por lo tanto 5 sera -5, y -2 sera 2.

    despues lo sigo faltan 5 mas

    El comentar no Produce ninguna enfermedad infectocontagiosa,
    valora el esfuerso de los que postean y comenta!!!
    gracias


  9. #9
    Administrator
    Puntos: 7,271, Nivel: 56
    Nivel completado: 61%, Puntos necesarios para el proximo Nivel: 79
    Actividad total: 10.1%
    Logros:
    100 Experience Points250 Experience Points500 Experience Points1000 Experience PointsRecommendation Second Class
    Charly tiene un aura espectacular Charly tiene un aura espectacular Charly tiene un aura espectacular Avatar de Charly
    Fecha de Ingreso
    Apr 2008
    Ubicación
    tigre. Bs.As Arg
    Edad
    33
    Mensajes
    1,362
    Puntos
    7,271
    Nivel
    56
    Gracias
    9
    Agradecido 1 Time in 1 Post

    Predeterminado Re: (tutorial) ensamblador y programacion

    Tutorial - parte 9

    Control del flujo de un programa

    Controlar el flujo de un programa es muy importante, ya que es donde podemos tomar decisiones de acuerdo a ciertas condiciones.

    Saltos incondicionales


    * La instrucción básica que transfiere el control a otro punto del programa es JMP.

    La sintaxis básica de la instrucción JMP es:

    JMP label (etiqueta)

    Para declarar una etiqueta o label en nuestro código, escribiremos su nombre seguido de dos puntos ":" al final, una etiqueta puede ser cualquier combinación de caracteres pero no puede comenzar con un numero, por ejemplo veamos 3 definiciones validas de labels:

    label1:
    label2:
    a:

    Una etiqueta puede ser declarada en una lÃÂ*nea aparte o antes de cualquier otra instrucción, por ejemplo:

    x1:
    MOV AX, 1

    x2: MOV AX, 2

    Compilad el siguiente ejemplo para la instrucción JMP:

    org 100h

    mov ax, 5 ; ajusta ax a 5.

    mov bx, 2 ; ajusta bx a 2.

    jmp calculo ; salta a 'calculo'.

    atras: jmp para ; salta a 'para'.

    calculo:

    add ax, bx ; suma bx a ax.

    jmp atras ; salta a 'atras'.

    atras:

    ret ; regrasa al sistema operativo.



    Por supuesto existen formas más simples de calcular la suma de dos números, pero aun es un buen ejemplo de la instrucción de salto libre JMP. Como podéis ver en el ejemplo la instrucción JMP es capaz de transferir el control del programa hacia adelante en el código o hacia atrás en el código. Puede saltar a cualquier punto dentro del segmento de código que se haya definido (code segment), en este caso 65,535 bytes.

    * Saltos Condicionales Cortos (Short)

    Al contrario que la instrucción JMP que realiza saltos incondicionales, hay instrucciones que realizan saltos que se ajustan a unas CONDICIONES, (realizando el salto solo cuando ciertas condiciones se producen). Estas instrucciones se dividen en tres grupos, el primer grupo solo comprueba una bandera o flag, el segundo grupo compara números con signo, y el tercero compara números sin signo.

    A) Instrucciones de salto condicional basadas en comprobar una bandera o flag:




    Como puedes haber notado hay varias instrucciones que provocan el mismo efecto, de modo que se ensamblan originando el mismo código maquina (machine code), luego es bueno recordar que cuando compilamos la instrucción JE – seria lo mismo que si ensamblásemos JZ, JC es ensamblada lo mismo que JB etc.

    Los diferentes nombres se emplean simplemente para que los programas sean más fáciles de entender, de programar e incluso lo que es más importante de recordar. Si desensamblásemos el código no sabrÃÂ*amos cual fue la instrucción original que provoca la aparición de un determinado código maquina ensamblado. En general se utiliza siempre de entre varias instrucciones similares aquella más común o simple.

    Si tu emulas el siguiente código veras que todas las instrucciones son ensambladas como JNB, el código maquina para esta instrucción es 73h con una longitud fija de dos bytes, donde el segundo byte es el numero de bytes a sumar al registro contador de programa o puntero (IP register) si la condición es cierta. Como la instrucción solo tiene 1 byte para guardar el offset que provoca el salto condicional, habrá un limite para el salto en el control del programa entre -128 bytes hacia atrás en el código o 127 bytes hacia delante en el código. Este offset es siempre con signo, de ahÃÂ* que se denominen saltos cortos.

    jnc etiqueta
    jnb etiqueta
    jae etiqueta
    mov ax, 4
    etiqueta:
    mov ax, 5
    ret

    B) Instrucciones de salto condicional basadas en comparar dos números con signo:



    <> - este sÃÂ*mbolo significa distinto (not equal).

    C) Instrucciones de salto condicional basadas en comparar dos números sin signo:




    Generalmente, cuando se requiere comparar valores numéricos se emplea la instrucción CMP (realiza lo mismo que la instrucción SUB (operación resta), pero no guarda el resultado, solo modifica las banderas (flags).

    La lógica es muy simple, por ejemplo:

    Se requiere comparar 5 y 2,

    5 - 2 = 3

    El resultado no es cero (la bandera Zero Flag se ajusta a 1).

    Otro ejemplo:

    Se requiere comparar 7 y 7,

    7 - 7 = 0

    El resultado es cero (la bandera Zero Flag se ajusta a 1 y JZ o JE realizaran el salto).

    He aquÃÂ* un ejemplo de la instrucción CMP y los altos condicionales:

    include "emu8086.inc"

    org 100h

    mov al, 25 ; ajusta al a 25.

    mov bl, 10 ; ajusta bl a 10.

    cmp al, bl ; compara al y bl.

    je igual ; jump if al = bl (zf = 1).

    putc 'N' ; si llega el programa aquÃÂ* significa que <> bl,

    jmp final ; luego saca a pantalla una 'N', y salta al final.

    igual: ; si llega el programa aquÃÂ*,

    putc 'S' ; entonces al = bl, y saca a pantalla una 'S'.

    final:

    ret ; regresa al S.O.




    Prueba el ejemplo anterior con números diferentes en AL y BL, pulsando en el emulador el botón flags para abrir la ventana donde se ven los valores actuales de las banderas mientras se va ejecutando paso a paso el código y comprueba lo que va pasando. Podéis usar F5 para recargar (reload) el programa en el emulador.

    * Bucles (Loops)




    Los Loops o Bucles son básicamente saltos como los vistos anteriormente, es posible programar loops sin utilizar la instrucción loop, por medio de emplear saltos condicionales que utilicen una comparación, que realmente es lo que estamos haciendo en el bucle.



    Todas las instrucciones de tipo loop utilizan el registro CX como contador, este es un registro de 16 y el valor máximo que puede almacenar es 65535 o FFFF, de cualquier forma se puede fácilmente anidar un loop dentro de otro, recursivamente, consiguiendo valores de repetición del bucle de 65535 * 65535 * 65535 ...hasta casi infinito... o agotando la ram o la pila de memoria (stack memory) que estemos empleando. Es posible almacenar el valor original del registro CX antes de cargar el valor del contado a utilizar en el utilizando la instrucción push cx (almacenándolo en la pila de memoria o snack) y recuperar dicho valor y colocarlo en el registro CX cuando hemos terminado el bucle mediante la instrucción pop cx, que recupera el valor desde la pila de memoria o snack, por ejemplo:



    org 100h



    mov bx, 0 ; contador total de veces que se realizan los bucles anidados.



    mov cx, 5



    bucle1:

    add bx, 1

    mov al, '1'

    mov ah, 0eh

    int 10h

    push cx

    mov cx, 5



    bucle2:

    add bx, 1

    mov al, '2'

    mov ah, 0eh

    int 10h

    push cx

    mov cx, 5



    bucle3:

    add bx, 1

    mov al, '3'

    mov ah, 0eh

    int 10h

    loop bucle3 ; bucle dentro de bucle.



    pop cx

    loop bucle2 ; bucle dentro de bucle.



    pop cx

    loop bucle1 ; bucle mas externo.



    ret



    El registro bx cuenta el total de veces que se realizan los 3 bucles anidados, mostrando el emulador su valor final en hexadecimal, si hacemos doble clic en el registro veremos su valor en decimal.

    Como otros saltos condicionales los loops tienen una instrucción compañera que puede ayudar a crear zonas de trabajo, cuando la dirección del lugar del programa a alcanzar esta demasiado lejos (far) para ser ensamblada automáticamente. Se utiliza una instrucción para saltos LARGOS, que emplea 5 bytes en vez de solo 2, para una explicación más detallada sobre los saltos largos y ejemplos utilice la lista completa de instrucciones.

    Todos los saltos condicionales tienen una gran limitación, a diferencia de la instrucción JMP solo pueden saltar 127 bytes adelante y 128 bytes hacia atrás (date cuenta que la inmensa mayorÃÂ*a de las instrucciones son ensambladas en 3 o mas bytes).

    Podemos fácilmente saltarnos esta limitación usando el siguiente truco:

    o Obtén una instrucción de salto condicional opuesta a la que quieres usar y haz que salte a la etiqueta label_x.
    o Usa la instrucción JMP para saltar al lugar deseado.
    o Define o coloca la etiqueta label_x: justo después de la instrucción JMP.

    label_x: - puede ser cualquier nombre de etiqueta valido, pero recuerda que no puede haber dos o mas etiquetas con el mismo nombre.

    Veamos un ejemplo:

    include "emu8086.inc"

    org 100h

    mov al, 5

    mov bl, 5

    cmp al, bl ; compara al - bl.

    ; je igual ; hay solo 1 byte

    jne no_igual ; salta si al <> bl (zf = 0).

    jmp igual

    no_igual:

    add bl, al

    sub al, 10

    xor al, bl

    jmp def_data

    db 256 dup(0) ; 256 bytes

    def_data:

    putc 'N' ; si el programa llega aqui significa que al <> bl,

    jmp final ; luego sacamos a pantalla 'N', y saltamos a final.

    igual: ; si el programa llega aqui significa que al = bl,

    putc 'S' ; luego sacamos a pantalla 'S'.

    final:

    ret





    Nota: la ultima versión del 8086 assembler automáticamente crea un salto mas grande reemplazando el salto condicional con el opuesto, añadiendo un GRAN salto incondicional. Para comprobar si tienes la ultima versión del emu8086 clic help-> check for an update en el menú.


    Otro método, aunque pocas veces usado es proporcionar un dato (immediate value) en vez de una etiqueta. Cuando el dato comienza con el sÃÂ*mbolo $ se realiza un salto relativo, de lo contrario el compilador calcula la instrucción que salta directamente al OFFSET dado. Por ejemplo:

    org 100h



    ; salto incondicional hacia adelante:

    ; salta los proximos 3 bytes + el mismo

    ; la instruccion en codigo maquina de una instruccion jmp corta son 2 bytes.



    jmp $3+2

    a db 3 ; 1 byte.

    b db 4 ; 1 byte.

    c db 4 ; 1 byte.

    ; salto condicional hacia atras 5 bytes:

    mov bl,9

    dec bl ; 2 bytes.

    cmp bl, 0 ; 3 bytes.

    jne $-5 ; salta 5 bytes atras

    ret



    faltan los cuadros en breve los pondre

    El comentar no Produce ninguna enfermedad infectocontagiosa,
    valora el esfuerso de los que postean y comenta!!!
    gracias


  10. #10
    Administrator
    Puntos: 7,271, Nivel: 56
    Nivel completado: 61%, Puntos necesarios para el proximo Nivel: 79
    Actividad total: 10.1%
    Logros:
    100 Experience Points250 Experience Points500 Experience Points1000 Experience PointsRecommendation Second Class
    Charly tiene un aura espectacular Charly tiene un aura espectacular Charly tiene un aura espectacular Avatar de Charly
    Fecha de Ingreso
    Apr 2008
    Ubicación
    tigre. Bs.As Arg
    Edad
    33
    Mensajes
    1,362
    Puntos
    7,271
    Nivel
    56
    Gracias
    9
    Agradecido 1 Time in 1 Post

    Predeterminado Re: (tutorial) ensamblador y programacion

    Procedimientos
    parte 10

    Un Procedimiento es una parte de código que puede ser llamada desde nuestro programa para realizar una tarea especÃÂ*fica y repetitiva. Los Procedimientos hacen que la programación sea más estructurada y fácil de entender. Habitualmente al terminar la ejecución de un procedimiento se regresa al punto del programa original desde donde fue llamado.

    La sintaxis para la declaración de un procedimiento es:



    nombre PROC
    ; código del procedimiento
    ; ...
    RET
    nombre ENDP


    nombre - es el nombre del procedimiento, que debe coincidir al comienzo y al final del mismo, para comprobar el correcto cierre de la declaración de un procedimiento.

    Probablemente, ya conocerás que la instrucción RET se emplea para regresar al sistema operativo. De la misma manera se emplea para regresar desde el código del procedimiento al punto de nuestro programa donde fue llamado mediante la instrucción CALL. De hecho cualquier programa en ensamblador es visto por el sistema operativo como un procedimiento.

    PROC y ENDP son directivas de compilación que no generan ningún tipo de código máquina, no son ensambladas. Sirven solo para indicar al compilador la dirección de memoria desde donde se llamo al procedimiento para poder regresar al terminar su ejecución y la dirección de memoria donde comienza y termina el propio código del procedimiento a ejecutar.

    La instrucción CALL se usa para ejecutar un procedimiento, trasladando el control del programa al mismo.

    Por ejemplo:



    ORG 100h

    CALL m1

    MOV AX, 2

    RET ; regresa al SO.

    m1 PROC

    MOV BX, 5

    RET ; regresa al punto de ;llamada.

    m1 ENDP

    END




    El ejemplo anterior llama al procedimiento m1, que ejecuta la instrucción MOV BX, 5, y regresa a la siguiente instrucción después de la llamada que es: MOV AX, 2.

    Hay varias formas de pasar parámetros a un procedimiento, la forma mas sencilla de pasar parámetros es mediante la utilización de registros; a continuación vemos otro ejemplo de un procedimiento que recibe dos parámetros en los registros AL y BL, multiplica dichos parámetros y devuelve el resultado en el registro AX:



    ORG 100h

    MOV AL, 1

    MOV BL, 2

    CALL m2

    CALL m2

    CALL m2

    CALL m2

    RET ; regresa al SO.

    m2 PROC

    MUL BL ; AX = AL * BL.

    RET ; regresa al programa.

    m2 ENDP

    END




    En el ejemplo anterior el valor del registro AL se actualiza cada vez que se llama al procedimiento, mientras el registro BL permanece sin cambios, por lo que este algoritmo calcula la cuarta potencia de 2, cuyo resultado final en el registro AX es 16 (o 10h).


    Veamos otro ejemplo, que usa un procedimiento para imprimir en pantalla el tÃÂ*pico mensaje Hola Mundo:



    ORG 100h

    LEA SI, msj ; carga la dirección de memoria donde esta el mensaje en el ;registro SI.

    CALL imprime_me

    RET ; regresa al SO.




    ================================================== =======

    ; este procedimiento imprime una cadena, que debe terminar con un cero al

    ; final (null terminated), la dirección de memoria de la cadena debe estar ; cargada en el registro SI:

    imprime_me PROC

    prox_car:

    CMP b.[SI], 0 ; busca un cero para finalizar

    JE para

    MOV AL, [SI] ; coge el siguiente carácter ASCII.

    MOV AH, 0Eh ; subfunción de interrupción.

    INT 10h ; uso de la interrupción para imprimir el carácter que este en AL.

    ADD SI,1 ; avanza el ÃÂ*ndice que permite recorrer la cadena.

    JMP prox_car ; vuelve para imprimir el siguiente carácter.

    para:
    RET ; regresa al punto de llamada desde el programa principal.
    imprime_me ENDP
    ================================================== ========
    msj DB 'Hola Mundo!', 0 ; cadena null terminated (terminada con un cero).

    END




    "b." – el prefijo antes del registro [SI] significa que vamos a comparar bytes, no words. Si necesitásemos comparar words usarÃÂ*amos el prefijo "w." en su lugar. Si uno de los operandos comparados fuese un registro no necesitarÃÂ*amos usar el prefijo ya que el compilador sabe el tamaño de cada registro.

    El comentar no Produce ninguna enfermedad infectocontagiosa,
    valora el esfuerso de los que postean y comenta!!!
    gracias


+ Responder Tema
Página 1 de 2 1 2 ÚltimoÚltimo

Temas Similares

  1. Programación en D
    Por Saucelle en el foro Soporte para software y hardware
    Respuestas: 2
    Último Mensaje: 05-31-2009, 02:41 PM
  2. Cursos de Programacion (1 solo link)
    Por CraneoCandente en el foro Manuales, Tutoriales y trucos
    Respuestas: 0
    Último Mensaje: 05-16-2009, 01:49 AM
  3. Programacion
    Por omarsva en el foro Pedidos de programas
    Respuestas: 1
    Último Mensaje: 11-04-2008, 09:26 PM
  4. Introduccion a la programacion Python
    Por chapio en el foro Manuales y Tutoriales
    Respuestas: 1
    Último Mensaje: 05-05-2008, 01:10 AM
  5. Programacion Visula Basic .net
    Por chapio en el foro Manuales y Tutoriales
    Respuestas: 0
    Último Mensaje: 05-04-2008, 10:49 PM

Visitors found this page by searching for:

Ningun usuario ingreso a esta seccion por un buscador!
SEO Blog

Etiquetas para este Tema

Marcadores

Permisos de Publicación

  • No puedes crear nuevos temas
  • No puedes responder temas
  • No puedes subir archivos adjuntos
  • No puedes editar tus mensajes
monitorización tiempo online servidor