Vistas de página en total

domingo, 30 de junio de 2013

LONGITUD DE UNA CADENA DE TEXTO


      Para completar la librería STRING de manejo de cadenas vamos a publicar las funciones más necesarias. La primera y básica es strlen. 
     Esta función que calcula la longitud de una cadena.
     En este caso

STRLEN.ASM
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.

include main.mac
_modelo exe
_code
rutina _strlen  testo
        push bx
        mov bx,[bp].texto
    MAS:
        cmp byte ptr [bx],0
        jz FIN
        inc bx
        jmp MAS
    FIN:
        sub bx,[bp].texto
        mov ax,bx
        pop bx
rutina_end
_data
_end

viernes, 28 de junio de 2013

PROGRAMA USO LIBRERÍA STDIO

    Este ya es el primer ejemplo complejo que  visualiza lo que he conseguido hasta ahora.
   Aunque simple, sería muy complicado editar y seguir un programa tan complejo directamente en ensamblador.
    Este programa es solo un ejemplo inicial de la operatividad de las funciones de STDIO.

    Este programa toma del teclado un texto y lo imprime. Luego toma un número, interpretándolo como decimal, y lo imprime posteriormente en decimal, binario, octal, hexadecimal, binario y en base 5.
    Como se puede ver el programa ya tiene los mensajes por pantalla y los posicionamientos tanto de mensajes como de entradas y salidas de textos  y variables.
    
    Con este ejemplo se puede ver igualmente, como se definirán las variables, apoyándonos en las definiciones hechas en MAIN.MAC.
    String, define una cadena y integer un entero. Para la salida de textos simples usamos simplemente una lista de bytes, con final en 0 que serán usados con puts.
    
    Dado que es un ejecutable la data la colocamos al comienzo, pues si no nos puede dar un error. En el caso de que fuese com la data la colocamos al final. Igualmente en _end damos el nombre de la rutina que debe ejecutarse.

      ¡Esto ya es My Assembler!   

     Recuerdo que seguimos compilando por debajo de MASM, pero a partir de ahora haremos maravillas....

EJEMPLO_1.ASM
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.


include main.mac
include stdio.mac

_modelo exe
_stack 512

_data
string cadena,30
integer valor 25
msgtexto db "Introduce un texto",0
msgvalor db "Introduce un numero decimal",0

_code
 p proc far
      main
      clrscr
      gotoxy 10,9
      puts msgtexto
      gotoxy 10,10
      scanf cadena
      gotoxy 20,10
      printf cadena
      gotoxy 10,11
      puts msgvalor
      gotoxy 10,12
      scanf valor
      gotoxy 20,12
      printf valor
      getch al
      gotoxy 20,13
      printf valor,@b
      getch al
      gotoxy 20,14
      printf valor,@o
      getch al
      gotoxy 20,15
      printf valor,@h
      getch al
      gotoxy 20,16
      printf valor,@d
      getch al
      gotoxy 20,17
      printf valor,5
      ret
  endp

_end ejemplo1



miércoles, 26 de junio de 2013

SCREEN


   En este caso en este fichero ASM incluimos las rutinas de borrado y posicionado en pantalla getxy, gotoxy, cls, y cls_window.
   Como vemos solo utilizo rutina (ver main) en las dos últimas funciones, ya que las primeras no necesitan parámetros y por lo tanto es más compacto no usar rutina. Al no llevar parámetros a través de  pila, no es necesaria la salvaguarda de puntero de pila y la posterior recuperación de esta.



SCREEN.ASM
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.

include main.mac
_modelo exe
_code
      public _getxy   ; necesario publicar al no haber sido definidas con "rutina"
      public _cls
      public _gotoxy

;devuelve la posicion del cursor
;devuelve x en al y en ah
_getxy proc near
        push bx
        push cx
        push dx
        mov ah,3
        mov bh,0
        int 10h
        mov ax,dx
        pop dx
        pop cx
        pop bx
        ret                           ; necesario por no ser definido con "rutina"
_getxy endp

;borra la pantalla con un color
;toma el color en Al
_cls proc near
        push bx
        push cx
        push dx
        mov bh,al
        mov ax,600h
        mov cx,0
        mov dx,194fh
        int 10h
        mov bx,0
        mov ah,2
        mov dx,0
        int 10h
        pop dx
        pop cx
        pop bx
        ret                                  ; necesario por no ser definido con "rutina"
_cls endp


; posicionael cursor
; la posición se pasa a través de pila
 _gotoxy proc near
        push dx
        push bx
        mov dx,ax
        mov bx,0
        mov ah,2
        int 10h
        pop bx
        pop dx
       ret
_gotoxy endp
_data
_end

lunes, 24 de junio de 2013

IMPRIMIR VARIABLES

 Vamos a montar la función de impresión de variables PRINTV, que es parte de la librería STDIO, y es llamada por la función   printf.
  Aprovechando esto, vamos a mejorar la cabecera MAIN.MAC, añadiendo una nueva macro.
   En la cabecera vamos a añadir:
            rutina_end macro
                   pop bp
                   ret
                   endp
             endm


  Esta nueva macro nos perimitirá, cerrar las rutinas de forma más sencilla sin necesidad de realizar la recuperación final de la pila ni el cierre del procedimiento. por lo tanto substituye a:

                   pop bp
                    ret
            _scanf endp


    Ahora simplemente deberemos colocar la palabra rutina_end.
    
    No resulta complejo esto, pues el código de la llamada a la función lo tenemos siempre en las macros y por lo tanto lo podemos adaptar fácilmente.
   En este caso hay que tener cuidado cuando usamos una macro como auxilio de una función. En este caso si necesitamos pasar los datos de la pila como parámetros a la macro, hay que tener en cuenta que los datos pasados por pila a la función que estamos creando ya son las direcciones de las variables de trabajo, por lo que no debemos usar una macro para llamar a la siguiente función si esta usa lea para obtener la dirección de la variable.
    Si hubiéramos usado la macro itoa, en vez de colocar mov habría colocado lea de [bp].var, y nos habría dado la dirección de la pila, no la dirección de la variable. Como en [bp].var ya tenemos la dirección de la variable, guardada por la macro printf, lo que debemos hacer es simplemente poner mov.
  Por todo esto, y dado que esto es algo puntual, pues se trata de la creación de nuevas librerías, cuando nos apoyemos en funciones, para crear nuevas funciones, debemos considerar que si usan en la macro la opción lea, debemos copiar el código de la macro, substituyendo los lea por mov, en vez de usarla como función.
  Tenemos que tener en cuenta que si no usamos la macro debemos declarar como externa la función a usar.
 Si podemos usar, en cambio, la macro puts.


PRINTV.ASM
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.

include main.mac
include stdio.mac
_modelo exe
   extrn _itoa:near  


_code

rutina _printv base,var,color
        push bx
        push cx
        push dx
        push si
        push di

      ; itoa buffer,[bp].var,[bp].base
        mov ax,[bp].base
        push ax
        mov ax,[bp].var
        push ax
        lea ax,buffer
        push ax
        call _itoa
        add sp,6

        puts buffer,[bp].color

        pop di
        pop si
        pop dx
        pop cx
        pop bx
rutina_end
_data
buffer db 33 dup (0)
_end

sábado, 22 de junio de 2013

ENTRADA POR TELCADO

    Como se puede ver ya vamos obteniendo resultados en el avance de la estructuración del lenguaje.
     Debemos tener en cuenta, que lo estamos haciendo con la versión más simple de compilador, y que lo estamos haciendo a nuestro modo. No me estoy adaptando a un compilador, estoy creando el mio propio.
    Es por eso que una vez se empieza este proceso, es muy difícil adaptarse a un compilador nuevo. por mucho que se sepa vender el nuevo compilador, siempre tendrá la visión de otra persona y siempre le faltarán cosas desde nuestro punto de vista.
    Es por ello por lo que, mi intención no es implementar in procedimiento, sino demostar a quien lea esto post, que no necesito un gran compilador para hacer grandes cosas, y que muchas veces es mejor partir de uno sencillo, porque me permitirá hacer las cosas a mi gusto.
   Cualquiera que vaya siguiendo estos pasos, ya habrá podido ver que puede cambiar los nombres de las macros, las funciones, o las etiquetas, para crear sus programas de forma más legible para él.

   Igualmente podrá facilmente ampliar cualquier parte, pues no hay nada oculto, ni a nivel de directivas de compilación.
    Más adelante, mostraré la forma de crear directivas de compilación para realizar if, while y for, de forma que al final estaremos creando un lenguaje basándonos en el simplemente en el compilador.

   Esta es la entrada estándar por teclado. Con ella, podremos solicitar entrada de cadenas o de variables.
   Lo interesante de este post es ver como ya vamos obteniendo resultados positivos del trabajo que hemos hecho hasta ahora en la estructuración y organización de nuestra librería.
    Como podéis ver el código fuente de esta librería es sumamente corto. Aunque seguimos trabajando en ensamblador, y seguimos usando un compilador muy, muy simple el TASM 2.0. Sin embargo solo esixten dos instrucciones de ensamblador (pop bp y ret) que pertenecen al fin de la rutina. Como ya habreis apreciado estas funciones se mantienen siempre al final de las rutinas, pues son la recuperación de la pila y el retorno a la función principal.
 
   En el siguiente Post haré una modificación para mejorar y completar esto, de manera que se vea lo facil que es hacer mejoras sin destruir nada de lo anterior.

  !OJO¡  Al usar variables que van a ser usadas como parámetros para una función ha de tenerse en cuenta que si la variable es local se usará su nombre, pero si ha sido pasada como parámetro a la función madre ha de usarse el formato [bp].nombre de la variable. Igualmente usamos Lea si la variable es local y mov si ha sido pasada como parámetro. por eso no usamos la macro sino la copiamos cambiando los lea por mov.
 
SACNF.ASM
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.

include main.mac
include stdio.mac
_modelo exe
_code
rutina _scanf dest, base
      gets numero
      ;atoi [bp].dest,numero+2,[bp].base

  ifndef _atoi
        extrn _atoi:near
  endif
        mov ax,[bp].base
        push ax
        lea ax,numero+2
        push ax
        mov ax,dest
        push ax
        call _atoi
        add sp,6


      pop bp
      ret
_scanf endp
_data
numero db 34,0,35 dup (0)
_end

jueves, 20 de junio de 2013

PUTS Y GETS


   Para ir completando la librería que corresponde a STDIO y poder usarla en nuestro primer ejemplo complejo, necesitamos crear las funciones de entrada y salida de cadena. Es decir, aquellas que nos permitirán, introducir e imprimir por pantalla un texto.
    Estas son _gets, _puts y _putchar usadas en las macros scanf y printf, como una de sus opciones.
    Como se ve la función está creada apoyándonos en la macro rutina de main.mac. Por ello debemos incluir main.mac al comienzo.
    Esta función como las demás que he ido poniendo debe de compilarse y luego almacenarse en la librería. Si usáis mis .BAT, se hará con lib.bat y se creará o almacenará dentro de la librería MASM.LIB.
   Lo más evidente de esta rutina es que el _puts no utiliza la función del dos equivalente, sino trabaja directamente sobre la memoria de pantalla en la dirección B000H. Por ello es más rápida que la equivalente del DOS.
 
     PUTSGETS.ASM
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.


include main.mac
_modelo exe
_code 
rutina _gets p1

        push es
        push di
        push dx
        push si
        mov dx, [bp].p1
        mov ah,0ah
        int 21h
        mov di, [bp].p1
        mov al, [di+1]
        xor ah, ah
        mov si, ax
        add si, di
        inc si
        inc si
        mov byte ptr [si],0
        pop si
        pop dx
        pop di
        pop es
        pop bp
        ret
_gets endp


;imprime un caracter con el color especificado en dh.
;el caracter esta en dl

rutina _putchar 
        mov caracter,al
        mov al,ah
        push ax
        mov ax,offset caracter
        push ax
        call _puts
        pop ax
        pop ax
        ret
 _putchar endp

rutina _puts p1,p2
     
        push es
        push SI
        push di
        push bx
        push dx
        push cx
        mov ax,40h
        mov es,ax
        mov dl,es:[4ah]
        mov al,es:[51h]
        xor dh,dh
        push dx
        mul dl
        xor dx,dx
        mov dl,es:[50h]
        add ax,dx
        shl ax,1
        mov di,ax
        mov al,es:[49h]
        cmp al,7
        jb sb800
        ja sa000
        mov ax,0b000h
        jmp listo

sb800:
        mov ax,0b800h
        jmp listo
sa000:
        mov ax,0a000h
 listo:
        mov bx,es:[4ch]
        sub bx,es:[4ah]
        sub bx,es:[4ah]
        mov es,ax
        mov si,[bp].p1
        mov ax,[bp].p2
        xchg ah,al
 _impr:
        mov al,[si]
        or al,al
        jz _fin_print
gestion:
        cmp al,0dh
        jnz s1
        pop dx
        push dx
        shl dx,1
        push ax
        mov ax,di
        div dl
        mul dl
        mov di,ax
        pop ax
        jmp short sin
s1:
        cmp al,0ah
        jnz s2
        pop dx
        push dx
        shl dx,1
        add di,dx
        jmp short sin
s2:
        cmp al,09h
        jnz con
        dec di
        dec di
        jmp short sin
 con:
        mov es:[di], ax
        inc di
        inc di
sin:
        inc si

;comprobar que di pasa de la longitud de pantalla y si es as¡ hacer un scroll
;de pantalla
        cmp di,bx
        jbe s3
        push ax
        push bx
        mov bh,ah
        mov ax,601h
        mov cx,0
        mov dx,184fh
        int 10h
        push es
        mov ax,40h
        mov es,ax
        sub di,es:[4ah]
        sub di,es:[4ah]
        pop es
        pop bx
        pop ax

 s3:
        jmp _impr

 _fin_print:
        pop dx
        shl dl,1
        mov ax, di
        div dl
        mov dh, al
        shr ah, 1
        mov dl, ah
        mov ah, 2
        mov bh, 0
        int 10h
        pop cx
        pop dx
        pop bx
        pop di
        pop SI
        pop es
        pop bp
        ret
_puts endp
_data 
caracter db 0,0
_end



martes, 18 de junio de 2013

DECLARACIÓN FUNCIONES DE IO TECLADO-PANTALLA


   Para poder realizar algún programa ya complejo vamos a colocar la que, creo es la cabecera y librería más básica. La STDIO. Como en C esta librería contendrá  los comandos y funciones para el manejo de la pantalla. En esta librería está incluidas la funciones de posicionamiento de cursor, impresión de textos y variables, y entradas de teclado.
   Además al comienzo incluyo las definiciones de constantes para el manejo del cursor, los colores y las variables numéricas.
 
    Las cabeceras son la forma de consultar la forma de llamar a cada función, por lo que siempre han de estar a mano. Las librerías sin embrago, serán compiladas y almacenadas en un .LIB, a partir del cual, ya no hace falta que tengamos a mano el código fuente.
 
     Como se ve en esta cabecera, algunas funciones como clswindow o clrscr, llaman a funciones auxiliares, ya que son más complejas de lo que se ve ahora.
      Un caso particular es la función printf. Esta es un ejemplo de programación condicional de macro. De esa forma conseguimos crear de  forma sencilla una función que en realidad son dos. Estamos creando realmente polimorfismo en ensambaldor.
    Que significa polimorfismo. Es una propiedad de los lenguajes Orientados a Objetos, por el cual se puede definir una función con varias formas, de manera que el compilador utilizará la adecuada en cada momento.

  Printf
     Pues bien, en este caso mediante las sentencias ifndef , ifidn e ifb  vamos a conseguir lo mismo. Según los parámetros que indiquemos al usar la función printf esta se comportará como la función puts(impresion de cadenas)  o la función printv (impresion de variables). 
    Igualmente si dirección es un byte, pero no se define base, se entiende que se usa base 10 como base de numeración. Si en cambio se indica una base entonces se interpretará en esa base.

    Ejemplos:
             Variables
                    m1 db 'primera linea ',10,13,'segunda linea',0 ; cadena de texto
                    A0 Dw 100h,0   ; variable numérica de palabra


             codigo
                      printf m1                        ; imprime texto
                      printf A0,@b                 ; imprime valor en binario
                      printf A0                        ; imprime valor en decimal

                      printf A0,5                     ; imprime valor en  base 5

    Exactamente sucederá con scanf que es la entrada de variables por teclado. podremos especificar si queremos leer una variable y en que sistema de numeración deberemos interpretarla.
   
     En las siguientes entradas iré exponiendo las rutinas asociadas a STDIO. Es decir las rutinas  _puts, _scanf, _getxy, etc que son llamadas desde las macros de esta cabecera. Después  estaremos en disposición de crear nuestro primer programa sobre pantalla que usen estas instrucciones, que nos serán absolutamente imprescindibles para crear pantallas de interface Hombre-Maquina.

   Otra ejemplo de este polimorfismo lo tenemos en _puts y printf. Estas macro está pensadas para ser usada con la variable de color por defecto o para ser usadas con un color pasado de forma puntual.
    Para ello usamos el siguiente código:
      ifb <color>
          mov ax,_color
       else
          mov ax,color
       endif


STDIO.MAC
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.


;Constantes para encendido y apagado del cursor
ON = 1
OFF = 0

;definición de bases para impresión de valores numéricos
ifndef _numeracion
   _numeracion equ 1
@b = 2
@o = 8
@d = 10
@h = 16
endif

; definición de colores y modos de testo
ifndef _colores
     _colores equ 1
parpadeo equ 80h
intenso equ 0fh
normal equ 7
subrayado equ 1
inverso equ 70h

negro equ 0
azul equ 1
verde equ 2
cian equ 3
rojo equ 4
magenta equ 5
marron equ 6
gris_claro equ 7
gris_obscuro equ 8
Azul_Claro equ 9
verde_claro equ 10
cian_claro equ 11
rojo_claro equ 12
magenta_claro equ 13
amarillo equ 14
blanco equ 15
endif

_color = normal


;Toma posición de cursor devuelve x en al e y en ah
getxy macro
ifndef _getxy
        extrn _getxy:near
endif
        call _getxy
endm

; Toma caracter de teclado
getch macro variable
    mov ah, 8
    int 21h
 ifdif <variable>,<al>
    mov variable, al
  endif
endm

;Toma caracter de teclado con eco
getche macro variable
    mov ah, 1
    int 21h
 ifdif <variable>,<al>
    mov variable, al
  endif
endm

;ZF = 1 si Vacio
;Lee si teclado pulsado
kbhit macro
        mov ah,1
        int 16h
endm

; borra pantalla
clrscr macro
ifndef _cls
        extrn _cls:near
endif
       call _cls
endm



;Posiciona el cursor en una coordenada
;La macro toma los dos parámetros y los combina en una sola palabra 
gotoxy macro px, py
ifndef _gotoxy
        extrn _gotoxy:near
endif
        mov al,px
        mov ah,py
        call _gotoxy

endm

;Selecciona un color
setcolor macro color
    _color = color
endm

;Imprime una cadena de texto string o variables
printf macro direccion,base,dest1,base1,color
ifndef _puts
        extrn _puts:near
endif

       ifb <color>
          mov ax,_color
       else
          mov ax,color
       endif

        push ax
ifidn <base>,<ptr>
        lea ax,dest1
else
        lea ax,direccion
endif
     
ifidn <base>,<ptr>
  ifidn <direccion>,<byte>

         add ax,2
         push ax

         call _puts
  else
       push ax
      ifb <base1>
         mov ax,10
      else
         mov ax,base1
      endif
      ifndef _printv
           extrn _printv:near
      endif
         push ax
         call _printv
         pop ax
   endif

 else
  if (type (direccion)) eq 1

         add ax,2
          push ax

         call _puts
  else
      push ax
      ifb <base>
         mov ax,10
      else
         mov ax,base
      endif
      ifndef _printv
           extrn _printv:near
      endif

         push ax
         call _printv
         pop ax
   endif
endif
         add sp,4
endm

; entrada de variables o testo string scanf macro direccion,base,dest1,base1
ifdif <base>,<ptr>
    if type (direccion) ne 1
       ifb <base>
          mov ax,10
       else
          mov ax,base
       endif
          push ax
     endif
        lea ax,direccion
        push ax
      if type (direccion) eq 1
        ifndef _gets
            extrn _gets:near
         endif
         call _gets
         pop ax
       else
         ifndef _scanf
             extrn _scanf:near
         endif
         call _scanf
         pop ax
         pop ax
       endif
else
    ifdif <direccion>,<byte>
       ifb <base1>
          mov ax,10
       else
          mov ax,base1
       endif
          push ax
     endif
        lea ax,dest1
        push ax
      ifidn <direccion>,<byte>
        ifndef _gets
            extrn _gets:near
         endif
         call _gets
         pop ax
       else
         ifndef _scanf
             extrn _scanf:near
         endif
         call _scanf
         add sp,4
       endif
endif
endm

;imprime texto simple puts macro  buffer
ifndef _puts
        extrn _puts:near
endif

       ifb <color>
          mov ax,_color
       else
          mov ax,color
       endif

        push ax
        lea ax,buffer
        push ax
        CALL _puts
        add sp,4
endm


; pide texto con formato string
gets macro  buffer
ifndef _puts
        extrn _gets:near
endif
        lea ax,buffer
        push ax
        CALL _gets
        pop ax
      
endm

putchar macro caracter
    push dx
ifdif <caracter>,<dl>
    mov dl, caracter
else 
    mov dl,al
endif
    mov ah,2
    int 21h
    pop dx
     
 endm

setcursor macro opcion
ifndef _set_cursor
        extrn _set_cursor:near
endif
        mov ax,opcion
        push ax
        call _set_cursor
        pop ax
endm





domingo, 16 de junio de 2013

ENTERO A CADENA

    Esta es la función contraria a la anterior. A esta función le daremos un valor numérico (32bits) y nos devolverá una cadena alfanumérica que representa el número en la base indicada. El formato de la función, como en el resto de mis funciones queda reflejado en la llamada a la función rutina
   
ITOA.ASM
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.

include main.mac
;_modelo com ; quitar el ; para  compilar para com

_code

rutina _itoa dest,dato,base
        push bx
        push cx
        push dx
        push si
        push di
        mov cx,[bp].base    ;recogida del parámetro base a la que se convertirá
        mov bx,[bp].dato   ;recogida del parámetro numero de 16 bits a convertir
        mov si,offset numero  ;puntero a la variable auxiliar para procesamiento del número
        mov di,[bp].dest     ;recogida del parámetro destino, donde se quiere dejar el string de salida
        mov ax,[bx]        ;tomamos el numero a procesar y lo guardamos en la variable número
        mov [si],ax        ; primer word
        mov dx,[bx+2]    ;segundo word
        mov [si+2],dx   
        cmp word ptr [bp].base,10   ;Verifica si la base es 10
        jne posit
        test word ptr [si+2],8000h  ; si la base es 10, verifica el signo en el bit alto
        jz posit
        xor word ptr [si],0ffffh      ; el signo es negativo y por lo tanto hace el complemento a 2
        xor word ptr [si+2],0ffffh
        add word ptr [si],1
        adc word ptr [si+2],0
        mov byte ptr [di],'-'        ; añade el signo a la cadena de salida
        inc di                              ; incrementa el puntero de salida
        mov puntero,di               ; almacena el puntero para el inicio la posterior formación del número   posit:

        xor di,di                       ;inica cuenta de caracteres , uso ahora di como contador  

         xor bh,bh                    ;inicia bh
  conv:
        mov ax,[si+2]           ;toma la parte alta del número
        xor dx,dx                ;borra el resto
        div cx                       ;divide por la base
        mov [si+2],ax        ; almacena el resultado
        mov ax,[si]        ;toma la parte baja
        div cx                ; divide por la base
        mov [si],ax    ;almacena el resultado
        mov bl,dl               ;toma el resto en bl, para indexar el caraceter
        mov dl,[bx+caracteres]       ; coge el caracter correspondiente al valor del resto
        push dx                         ;almacena en pila el caracter interpretado, para recogerlo luego en ax
        inc di                         ;incrementa di, usado como contador de caracteres
        cmp byte ptr [si],0    ;Ha terminado la conversión si el número ya es 0
        jne conv
        cmp byte ptr [si+2],0
        jne conv
        mov cx,di               ;almacena el contador en cx para la copia
        mov di,puntero; recupero el valor de DI como puntero al destino
   final:
        pop ax                  ; recupera el caracter interpretado
        mov [di],al         ;almacena el caracter en la cadena
        inc di                  ;incrementa el puntero
        loop final           ; continua la copia
        mov byte ptr [di],0    ; coloca el 0 de final de cadena
        pop di
        pop si
        pop dx
        pop cx
        pop bx
        pop bp
        ret
_itoa endp
_data
caracteres db "0123456789ABCDEF"
numero dd 0
puntero dw 0
_end






viernes, 14 de junio de 2013

CADENA A ENTERO

  Esta función, que es parte de la cabecera STRING. Nos permitirá convertir cualquier cadena de caracteres, que represente un número en cualquier base, a su valor numérico en un valor entero.

    En este caso como puede verse, nos hemos apoyado en la función anterior _may, la cual no se llamada a través de la macro strupr definida en STRING.MAC, sino  copiando el código de la macro.
    Esto es debido que la macro usa lea para tomar la dirección de la variable, y en este caso la dirección la tomamos del dato que ya se ha pasado por pila.

    Como ya habíamos definido la cabecera STRING.MAC, ahora podemos usarla en esta función, para directamente usar la función que necesitamos y que ya hemos implementado. Es decir strupr. por ello al comienzo de la función incluimos las cabeceras main ( para usar rutina) y string ( para usar strpur).

ATOI.ASM
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.

include main.mac
include string.mac
_modelo exe
_code

      extrn _may:near
rutina _atoi dest,text,base
        push bx
        push cx
        push dx
        push si
        push di
        mov di,offset numero
   nuevo:

       ;strupr [bp].text
         ifndef _may
              extrn _may:near
         endif
        mov ax,[bp].text
        push ax
        call _may
        pop ax

        mov bx,ax
        cmp word ptr [bp].base,10
        jne otro
        cmp byte ptr [bx],'-'            ;;compruevo si es negativo
        jne otro
        inc bx
 otro:
        mov cx,[bp].base                 ;busqueda de caracter entre los definidos
        mov si,offset caracteres         ;en la base de numeracion
        mov al,[bx]
    busca:
        cmp al,[si]
        jz encont
        inc si
        loop busca
    encont:
        or cx,cx
        jz analisis
        mov ax,si
        sub ax,offset caracteres
        mov [di],al
        inc di
        inc bx
        cmp byte ptr  [bx],0
        jnz otro
   analisis:
        dec di
        mov bx,di
        mov di,[bp].dest        ;direccion de la variable dword
        mov word ptr [di],0
        mov word ptr [di+2],0
        mov multl,1               ;peso del bit 1,2,4,8
        mov multh,0
        mov cx,[bp].base         ;base de numeracion

  acum:
        mov al,[bx]
        cbw
        mov si,ax
        mov ax,multl
        mul si
        add [di],ax
        adc [di+2],dx
        mov ax,multh
        mul si
        add [di+2],ax
        mov ax,multh
        mul cx
        mov multh,ax
        mov ax,multl
        mul cx
        mov multl,ax
        add multh,dx

        dec bx                   ;sigiente numero
        cmp bx,offset numero-1
        je fin
        cmp byte ptr [bx],'-'
        jne acum
        xor word ptr [di],0ffffh
        xor word ptr [di+2],0ffffh
        add word ptr [di],1
        adc word ptr [di+2],0
  fin:  pop di
        pop si
        pop dx
        pop cx
        pop bx
        pop bp
        ret
_atoi endp

_data
caracteres db "0123456789ABCDEF"
numero db 33 dup (0)
multl dw 0
multh dw 0
_end




miércoles, 12 de junio de 2013

PASO A MAYUSCULAS

    Para crear lo básico de STRING, comenzaremos por la función de paso a mayusculas de una cadena. La función la llamo MAY aunque la macro se llama STRUPR.
   Esta función es necesaria para posteriormente convertir las cadenas en números en ATOI.



MAY.ASM

; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.

include main.mac
_modelo exe
_code 
rutina _may text
        push bx
        mov bx,[bp].text
mayusc:
        cmp byte ptr [bx],0
        je fin
        cmp byte ptr [bx],'a'
        jb otro
        cmp byte ptr [bx],'z'
        ja otro
        sub byte ptr [bx],'a'-'A'
        jmp otro1
otro:
        cmp byte ptr [bx],'¤'
        jne otro1
        mov byte ptr [bx],'¥'
otro1:
        inc bx
        jmp mayusc
fin:
        pop bx
        pop bp
        ret
endp
_data
_end

lunes, 10 de junio de 2013

DECLARACIÓN FUNCIONES DE CADENA

        Vamos a ver y crear parte de la librería STRING, la cual servirá para el manejo de cadenas. Es importante hacer parte de esta librería enseguida pues en ella tenemos la función itoa y atoi, que vamos a necesitar en las funciones Scanf y Prinf de la librería básica STDIO.
     Por ello comenzaré con la  cabecera STRING.MAC y posteriormente las funciones atoi y itoa, para poder realizar una parte muy importante de la librería que necesitaremos posteriormente para la librerías STDIO.
    Con esta parte de String y la posterior STDIO, estaremos ya en condiciones de hacer nuestros primeros programas de entrada y salida de texto y valores por pantalla.
 
     Como veis, no hace falta decir mucho de las funciones, pues son estructuras iguales a las anteriores, para las llamadas a las funciones auxiliares. Los nombres son parecidos a los usados en C.
      Con estas funciones podremos manejar los textos que entremos por teclado y presentarlos de forma adecuada. Igualmente, cuando más tarde creemos la librería FILE y IO, podremos crear bases de datos con sus ALTAS-BAJAS-MODIFICACIONES.
       Como podemos crear la macro, pero no usarla, podremos hacer el fichero .MAC con todas las funciones, pero solo implementar en la librería itoa y atoi. Lo haremos así, dejando el resto para después de los primeros ejemplos.


STRING.MAC
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.

;pasa el caracter al a mayusculas
; se le puede pasar o no parámetro.
; Si no se le pasa parámetro asume que se pasa a mayusculas al
upr macro letra 
local salir
ifnb <letra>
        mov al,letra

endif
        cmp  al,'a'
        jb salir
        cmp al,'z'
        ja salir
        sub al,'a'-'A'
salir:
ifnb <letra>
        mov letra,al

endif
        endm

;pasa la cadena a mayusculas
strupr macro direccion
ifndef _may
    extrn _may:near
endif
        lea ax,direccion
        push ax
        call _may
        pop ax
endm

;devuelve la longitud de la cadena
STRLEN MACRO CADENA
ifndef _strlen
    extrn _strlen:near
endif
       lea AX,CADENA
       PUSH AX
       CALL _STRLEN
       ADD SP,2
ENDM

;compara dos cadenas devuelve las banderas como en una comparacion normal
strcmp macro destino,fuente
ifndef _strcmp
    extrn _strcmp:near
endif
        lea ax,fuente
        push ax
        lea ax,destino
        push ax
        call _strcmp
        pop ax
        pop ax
 endm

strcpy macro destino,fuente
ifndef _strcpy
    extrn _strcpy:near
endif
        lea ax,fuente
        push ax
        lea ax,destino
        push ax
        call _strcpy
        pop ax
        pop ax
 endm

strcut macro destino,inic,fin,fuente
ifndef _strcut
     extrn _strcut:near
endif
        lea ax,fuente
        push ax
        mov ax,fin
        push ax
        mov ax,inic
        push ax
        lea ax,destino
        push ax
        call _strcut
        add sp,8
 endm

strcat macro destino,fuente1,fuente2
 ifndef _strcat
      extrn _strcat:near
 endif
        lea ax,fuente2
        push ax
        lea ax,fuente1
        push ax
        lea ax,destino
        push ax
        call _strcat
        add sp,6
  endm


atoi macro destino,texto,base
  ifndef _atoi
        extrn _atoi:near
  endif
  ifb <base>
        mov ax,10
  else
        mov ax,base
  endif
        push ax
        lea ax,texto
        push ax
        lea ax,destino
        push ax
        call _atoi
        add sp,6
   endm


itoa macro destino,numero,base
ifndef _itoa
        extrn _itoa:near
endif
ifb <base>
        mov ax,10
else
        mov ax,base
endif
        push ax
        lea ax,numero
        push ax
        lea ax,destino
        push ax
        call _itoa
        add sp,6
 endm



sábado, 8 de junio de 2013

EXPONENTE

   Hoy vamos a dar una vuelta de tuerca a la estructura de programación.
   Visto ya como se utilizaba la función rutina de la cabecera MAIN.MAC, para crear fácilmente las cabeceras de las rutinas y simplificar el código fuente de ensamblador, vamos ahora a ver como hacer lo mismo con el resto de las cabeceras, de forma que vamos a usar varias funciones ya creadas para crear una más compleja.
  El resultado volverá a ser como intentamos desde el principio, un programa en ensamblador con apariencia de alto nivel. Cuanto más cabeceras y rutinas hayamos  implementado, más simple queda el programa, utilizando el ensamblador puro simplemente para las inicializaciones de pilas y las características propias de la rutina implementada en el código en curso.

    En este caso para realizar el exponente necesitaremos apoyarnos en el factorial, en la potencia, en la suma y en la división. Como la definición de sus macros está en la cabecera MATH.MAC, la cabecera la incluirémos en el programa mediante include al igual que hacemos con MAIN.MAC para poder usar la macro rutina.

   El resultado, como se ve, es una código que declara las cabeceras, de las cuales tomaremos la forma uso de cada función, y en la que no importa que este incluida la declaración de la macro de la propia función exp, para simplificar el código.
    Como vemos lo primero es tomar las variables pasadas a la función como parámetros y guardarlos en las variables locales. De esta forma podemos utilizar esta como parámetros de paso para las funciones auxiliares, usando las macros para ello.

EXP.ASM
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.

include main.mac      ; inclusion de la cabecera main para uso de rutina
include math.mac     ; inclusion de la cabecera math, para usar pot, fac, divi y suma

; no poner _modelo exe  equivale a definir tipo exe

_code
rutina _exp exponente,resultado      ;declaración de la función con sus variables de paso
        push bx      ;salvaguarda de registros usados
        push di
        mov ax,[bp].exponente
        mov x,ax
        mov x+2,0
        mov di,[bp].resultado
        mov n,0
        mov word ptr [di],0
        mov word ptr [di+2],0
   mas:
        pot x,n,aux       ;llamada a la función potencia
        fac n,aux1        ; llamada a la función factorial
        divi aux,aux1,aux2    ;División
        suma [di],aux2,[di]   ;Suma
        inc n
        cmp n,13
        jnz mas
        pop di   ; recuperación de registros usados
        pop bx
        pop bp
        ret
_exp endp

_data             ;variables locales usadas por esta función
n dw 0,0       ;variables locales usadas por esta función
x dw 0,0
aux dd 0
aux1 dd 0
aux2 dd 0
_end



jueves, 6 de junio de 2013

DIVIDIR


Función dividir de la librería matemática Math.



DIVI.ASM
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.

;; solo divide por numeros menores de ffffh
include main.mac
_modelo exe

_code
rutina _divi dividendo,divisor,resultado
        push bx
        push dx
        push cx
        push si
        push di
        mov si,[bp].dividendo
        mov di,[bp].resultado
        mov bx,[bp].divisor
        mov word ptr [di+2],0
        mov word ptr [di],0
        xor dx,dx
        cmp word ptr [bx+2],0
        jz normal
        mov ax,[si+2]
        cmp ax,[bx+2]
        jb fin
        mov cx,[bx+2]
        div cx
        mov [di],ax
comprueba:
        mul word ptr [bx]
        mov aux,ax
        mov aux+2,dx
        mov ax,[di]
        mul word ptr [bx+2]
        add aux+2,ax
        mov ax,aux+2
        cmp ax,[si+2]
        ja no_cabe
        jne fin
        mov ax,aux
        cmp ax,[si]
        jbe fin
no_cabe:
        dec word ptr [di]
        mov ax,[di]
        jmp comprueba

  normal:
        mov cx,[bx]
        mov ax,[si+2]
        div cx
        mov [di+2],ax
        mov ax,[si]
        div cx
        mov [di],ax
   fin:
        pop di
        pop si
        pop cx
        pop dx
        pop bx
        pop bp
        ret
_divi endp
_data
aux dw 0,0
_end






martes, 4 de junio de 2013

RAIZ CUADRADA

Rutina que nos permite sacar la raíz cuadrada.

 No hay mucho que explicar pues la estructura se basa en lo mismo.
  Sabemos que existen coprocesadores con coma flotante en un PC. Pero cuando se enseña ensamblador, hay que tener en cuenta que no todos los procesadores lo tienen. Aprender ensamblador, significa aprende también microprocesadores. En la actualidad, muchos microcontroladores se programan en "C" o "basic", pero quizás por testarudez, a mi me gustan los microprocesadores directos.
   Este es un ejemplo de calculo de la raíz cuadrada por el método recurente, (Algoritmo Babilónico). En este caso solo obtenemos la parte entera, pero en muchos casos de pequeños programas de control nos servirá.
  Si queremos obtener decimales, bastará con multiplicar el número previamente por 100 o 10000 y luego aplicar el algoritmo. Después simplemente descomponemos la parte entera que nos haya resultado. Por ejemplo (Raiz de 3) = (Raiz de 300) /10.
   por ello si queremos un decimal, multiplicamos 3*100=300, aplicamos el algoritmo y nos da 17, y dividiendo por 10, la parte entera es la palrte entera y el resto son los decimales =1.7.

  Es un buen ejemplo de como obtener de forma matemática una función complicada, como la raíz cuadrada, mediante funciones simples.
  El método es el de Newton-Raphson, el cuál se basa en una serie de Taylor, para obtener el valor de una función dada. Si quieres saber más acerca de este método, mira en Wikipedia.
      El valor de una raíz cuadrada lo vamos a ir a aproximando de está forma:
 Para una raiz N, y teniendo una aproximación APROX, mi siguiente aproximación va a ser igual a:

APROX = APROX - (APROX * APROX - N) / (2 * APROX)

Este proceso lo repetimos hasta que la aproximación no cambie, o cuando los cambios de ésta sean mínimos (depende de que tan precisa quieres la raíz). Ej:

N=3
APROX = 1 (El valor inicial no importa)

APROX = 1 - ( 1 * 1 - 3) / (2 * 1) = 2
APROX = 2 - ( 2 * 2 - 3) / (2 * 2 ) = 1.75
APROX = 1.75 - (1.75 * 1.75 - 3) / (2 * 1.75) = 1.73215
YA APROXIMAMOS LA RAÍZ DE 3!!


SQR.ASM
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.
; codigo
; raiz cuadrada. devuelve en ax el resultado

include main.mac
include math.mac
_modelo exe
_code
rutina _sqr p1

        push bx
        push si
        mov bx,[bp].p1
        mov si,offset n
        mov ax,[bx]       ;COPIAMOS EL DATO PASADO 
        mov [si],ax        ;N=P1
        mov ax,[bx+2]
        mov [si+2],ax
        MOV CX,2          ;MULTIPLICADOR 2
        ;COMIENZA LA ITARACIËN
        mov AX,1       ;APROX=1
    sig:        
        MOV APROX,AX
        MUL CX       ;2*APROX
        MOV AAPROX,AX
        MOV AAPROX+2,DX
        POT APROX,2,APROX2         ;APROX^2
        RESTA APROX2,N,APROX3
        DIVI  APROX3,AAPROX,APROX4
        MOV AX, APROX
        SUB AX, APROX4
        CMP AX, APROX
        jne sig
  
        pop si
        pop bx
        pop bp
        ret
_sqr endp
_data 
APROX DW 0,0
AAPROX DW 0,0
APROX2 DW 0,0
APROX3 DW 0,0
APROX4 DW 0,0
N DW 0,0
_end

domingo, 2 de junio de 2013

SUMA

De forma idéntica a la resta tenemos la suma.

SUMA.ASM
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.

; codigo
include main.mac
_modelo exe
_code
rutina _suma sum1,sum2,res
         push bx
        push si
        push di
        mov si,[bp].sum1
        mov bx,[bp].sum2
        mov di,[bp].res
        mov ax,[si]
        add ax,[bx]
        mov [di],ax
        mov ax,[si+2]
        adc ax,[bx+2]
        mov [di+2],ax
        pop di
        pop si
        pop bx
        pop bp
        ret
_suma endp
_data
_end