Vistas de página en total

Mostrando entradas con la etiqueta fac. Mostrar todas las entradas
Mostrando entradas con la etiqueta fac. Mostrar todas las entradas

jueves, 23 de mayo de 2013

DECLARACIÓN FUNCIONES MATEMÁTICAS

    Ya que en la anterior entrada hemos colocado una función matemática, la función fac, continuaremos con la librería matemática.
   En este cas, como en todos, si el código no supera un determinado tamaño no se pasa a librería y se implementa como macro.
 ¿Cual es el tamaño para el cambio?. Si el tamaño que resulta de guardar los datos en pila, la inicialización de pila, y recuperación de la pila,  es mayor que tamaño en si del código de la función.

   Así pues, todas estas funciones son implementadas mediante macros que llaman a funciones, menos la comparación.

     En todas la macros existe la instrucción ifndef, para que no implemente el compilador la función en el código mas que una vez y no declare la función como externa si no es usada. De esta forma el linkador no cargará la rutina de la librería, pues no ha sido declarada.


MATH.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/>.
; cabecera funciones matemáticas

@b = 2  ;binario
@o = 8   ;octal
@d = 10  ;decimal
@h = 16 ;hexadecimal


; res=ope1 + ope2
suma macro ope1,ope2,res
ifndef _suma
       extrn _suma:near     
endif
        lea ax,res
        push ax
        lea ax,ope2
        push ax
        lea ax,ope1
        push ax
        call _suma
        add sp,6
     endm

; res=ope1 -ope2
resta macro ope1,ope2,res
ifndef _resta
       extrn _resta:near
endif
        lea ax,res
        push ax
        lea ax,ope2
        push ax
        lea ax,ope1
        push ax
        call _resta
        add sp,6
     endm

; res=ope1 * ope2
mult macro ope1,ope2,res
ifndef _mult
       extrn _mult:near
endif
        lea ax,res
        push ax
        lea ax,ope2
        push ax
        lea ax,ope1
        push ax
        call _mult
        add sp,6
     endm

; res=ope1 / ope2
divi macro ope1,ope2,res
ifndef _divi
       extrn _divi:near
endif
        lea ax,res
        push ax
        lea ax,ope2
        push ax
        lea ax,ope1
        push ax
        call _divi
        add sp,6
     endm

;sqr devuelve en ax el resultado de la raiz
sqr macro oper
ifndef _sqr
        extrn _sqr:near
endif
        lea ax,oper
        push ax
        call _sqr
        add sp,2
      endm

;fac calcula el factorial del int fuente y lo devuelve en destino
;destino=factorial(fuente)
fac macro fuente,destino
ifndef _fac
       extrn _fac:near
endif
        lea ax,destino
        push ax
        lea ax,fuente
        push ax
        call _fac
        add sp,4
  endm

;pot calcula x a la n siendo x=fuente,n=potenc y devuelve el resultado en destino
pot macro fuente,potenc,destino
ifndef _pot
       extrn _pot:near
endif
        lea ax,destino
        push ax
        mov ax,potenc
        push ax
        lea ax,fuente
        push ax
        call _pot
        add sp,6
  endm

; destino=
exp macro potenc,destino
ifndef _exp
       extrn _exp:near
endif
        lea ax,destino
        push ax
        mov ax,potenc
        push ax
        call _exp
        add sp,4
  endm

cmpi macro destino,fuente
local fin

     push ax
     mov ax,fuente+2
     cmp destino+2,ax
     jne fin
     mov ax,fuente
     cmp destino,ax
 fin:
     pop ax
     endm

martes, 21 de mayo de 2013

APROVECHANDO MAIN.MAC (Función FACTORIAL)

  Vamos ahora a pormenorizar un poco lo que hemos visto anteriormente.
  En el ejemplo de las rutinas de gráficos hemos visto como con un código inicial muy pequeño hemos generado un código más grande.
   ¿Pero que hemos hecho realmente?
  lo que hemos hecho es usar la pila como zona de paso de datos, es decir de interface entre la rutina y el programa que la llama. Pero para que no tengamos que estar contando los indices de pila y memorizando que el primero que metimos era el bp, el siguiente la dirección de retorno, el tercero el x, etc hemos usado una estructura.

Para ello vamos a ver otra rutina. En este caso parte de la librería MATH. La rutina de factorial.
Primero la vamos a ve generada con la estructura y luego con la macro rutina.

FAC.ASM (sin apoyarnos en main.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/>.
 ;estructura  paso de parámetros a través de pila. 
_parametros struc
        _bp dw ?
        _ret dw ?
        p1  dw ?     ;;primer sumando
        p2  dw ?     ;;segundo sumando
        p3  dw ?     ;;resultado
        p4  dw ?
        p5  dw ?
        p6  dw ?
        p7  dw ?
        p8  dw ?
 ends

; codigo
code segment byte public 'code'
      assume cs:code,ds:data
      public _fac
      extrn _mult:near
_fac proc near
        push bp
        mov bp,sp
        push bx
        push di
        mov bx,[bp].p1 , indexación a través de la estructura para recoger el parametro p1
        mov di,[bp].p2
        mov word ptr [di],1
        mov word ptr [di+2],0
        mov word ptr aux,0
        mov word ptr aux+2,0
 otro:
        mov ax,[bx]
        cmp aux,ax
        jnz no
        mov ax,[bx+2]
        cmp aux+2,ax
        jz fin
     no:
        add aux,1
        adc aux+2,0
        push di
        push di
        mov ax,offset aux
        push ax
        call _mult
        add sp,6
        jmp otro
   fin:
        pop di
        pop bx
        pop bp
        ret
_fac endp
code ends
data segment byte public 'data'
aux dw 0,0
data ends
end


  Como se puede apreciar el código está bastante claro al haber usado la estructura, ya que nos ha permitido direccionar fácilmente los datos de intercambio en pila.
  Pero ahora vamos a hacer el código usando main.mac y la macro rutina.


FAC.ASM (apoyarnos en main.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/>.

; codigo
include main.mac    ; incluimos las macros y nuestras propias directivas de compilación
extrn _mult 
_modelo exe         ;directiva propia para elegir forma de colocar la data en la función
_code                   ;directiva propia. definición del segmento de codigo
rutina _fac p1,p2   ;directiva propia  definición de función con parámetros
        push bx
        push di
        mov bx,[bp].p1 ; indexación a través de la estructura para recoger el parametro p1
        mov di,[bp].p2
        mov word ptr [di],1
        mov word ptr [di+2],0
        mov word ptr aux,0
        mov word ptr aux+2,0
 otro:
        mov ax,[bx]
        cmp aux,ax
        jnz no
        mov ax,[bx+2]
        cmp aux+2,ax
        jz fin
     no:
        add aux,1
        adc aux+2,0
        push di
        push di
        mov ax,offset aux
        push ax
        call _mult
        add sp,6
        jmp otro
   fin:
        pop di
        pop bx
        pop bp
        ret
_fac endp
_data          ;directiva propia  definición de zona de datos
aux dw 0,0
_end           ; directiva propia. Fin de programa. En este caso no damos nombre pues es librería.


  Como vemos ha quedado más simple.  Igualmente se podría realizar una macro para salvar todos los registros a pila al inicio, pero entonces el código crearía volcados y recuperaciones de registros a pila inútiles. Como lo que queremos con el ensamblador es no crear ni un solo byte innecesario, es mejor sacrificar esa comodidad si implica código basura.