Vistas de página en total

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

viernes, 4 de abril de 2014

FILL RECTANGLE

Función para realizar RECTANGULOS RELLENOS apoyandolnos en la función LINEA.

Macro DE LLAMADA para ampliar en GRAPHICS.MAC

GRAPHICS.MAC
;Dibuja un rectangulo lleno
fillrectangle macro x0,y0,x1,y1,color
ifndef _fillrectangle
        extrn _fillrectangle:near
endif
        mov ax,x0
        push ax
        mov ax,y0
        push ax
        mov ax,x1
        push ax
        mov ax,y1
        push ax
        mov ax,color
        push ax
        call _fillrectangle
        

 endm  


FRECTAN.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/>.
.model compact,pascal

        public _fillrectangle
.data

.code
       ;algoritmo Bresenham
_fillrectangle proc uses ax cx bx ,x0,y0,x1,y1,color
        mov cx,y0
        mov bx,y1
        mov ax,y0       ;COMPRUEBA EL MAYOR PARA ORDENAR EL BUCLE
        cmp ax,y1
        jbe correcto
        ;invertir  las y
        mov cx,y1       
        mov bx,y0
correcto:                        ;BUCLE DE LÍNEAS
        line x0,cx,x1,cx,color
        inc cx
        cmp cx,bx
        jne correcto
        ret
_fillrectangle endp

end

miércoles, 2 de abril de 2014

RECTANGLE


Función para realizar rectangulos apoyandolnos en la función linea.

Macro DE LLAMADA para ampliar en GRAPHICS.MAC

GRAPHICS.MAC
;Dibuja un rectangulo
rectangle macro x0,y0,x1,y1,color
ifndef _rectangle
        extrn _rectangle:near
endif
        mov ax,x0
        push ax
        mov ax,y0
        push ax
        mov ax,x1
        push ax
        mov ax,y1
        push ax
        mov ax,color
        push ax
        call _rectangle
       
 endm 




RECTAN.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 graphics.mac


.model compact,pascal

        public _rectangle
.data

.code
       ;algoritmo Bresenham
_rectangle proc uses ,x0,y0,x1,y1,color
        line x0,y0,x1,y0,color
        line x0,y1,x1,y1,color
        line x0,y0,x0,y1,color
        line x1,y0,x1,y1,color
        ret
_rectangle endp

end

viernes, 28 de marzo de 2014

DISTANCIA ENTRE DOS PIXEL

    Para poder realizar el ejemplo con circulos, necesito poder pasar a la función circle el radio, tomandolo de la posición dadapor el ratón. Es decir el primer punto que elija con el ratón será el origen del circulo y el  segundo punto será un extremo que definirá el radio.
   Por lo tanto necxesitamos una funcion que nos permita calcular la distancia desde el primer punto al segundo, dado que esa distancia será el radio.
  
   Como esta acción es muy interesante para otras aplicaciones, nos conviene generar una rutina y no aplicar el algoritmo directamente al programa de ejemplo. Aunque lleve un poco más de trabajo valdrá la pena.





A añadir a GRAPHICS.MAC

;definición de la llamada a Dist_pixel
;se le pasan las coordenadas de dos puntos y devuelve en ax la distancia
Dist_pixel macro x0,y0,x1,y1
ifndef _dist_pixel
     extern _dist_pixel
endif
        mov ax,x0
        push ax
        mov ax,y0
        push ax
        mov ax,x1
        push ax
        mov ax,y1
        push ax       call _dist_pixel
endm



DPIXEL.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 math.mac

;mide la distancia entre dos pixel
;se le pasa las coordenadas de los dos puntos y nos devuenve en ax la distancia en pixel
    public _dist_pixel
model compact,pascal
.data
radio dw 0,0
ix dw 0,0    ;valor absoluto incremento x
iy dw 0,0     ; valort absoluto incremento de y
ix2  dw 0,0  ; cuadrado del incremento x
iy2  dw 0,0  ;cuadrado del incremento y
.code
_dist_pixel proc uses ,x0,y0,x1,y1

        mov ax,y1
        sub ax,y0        ;(y1-y0)
        abs ax         
        mov iy,ax        ;dy=abs(y1-y0)
        pot iy,2,iy2     ;dy2=dy^2
        mov ax,x1
        sub  ax,x0      ;(x1-x0)2
        abs ax         
        mov ix,ax        ;dx=abs(x1-x0)
        pot ix,2,ix2     ;dx2=dx^2
      
        suma ix2,iy2,radio     ;(y1-y0)^2+(x1-x0)^2  
      
        sqr radio
        ret
_dist_pixel endp

end

miércoles, 26 de marzo de 2014

CIRCLE

   Siguiendo las funciones gráficas, la siguinete depues de la línea en impritancia es el circulo.
Al igual que he hecho con la línea utilizaré el algoritmo de Bresenham.

 
  El pseudocódigo del algoritmo es:
 
*Se capturan el radio r y el centro de la circunferencia (xc, yc).
 *Se obtiene el primer punto de la circunferencia centrada en origen (xc, yc) como (0, r).
 *Se cacula el valor inicial del parametro de decisión como p0=5/4 - r.
 Para k=0 hasta x>=y incrementa k
    Si pk < 0 
       *Siguiente punto de la circunferencia con centro (0,0) es (xk+1, yk).
       *pk+1=pk+2xk+1+1.
    Sino
        *Siguiente punto de la circunferencia con centro (0,0) es (xk+1, yk-1).
       *pk+1=pk+2xk+1+1-2yk+1.
    //Donde 2xk+1=2xk+2  y  2yk+1=2yk-2
 
 *Se determinan los puntos de simetría para los otros siete octantes.
 *Se mueve cada posición del pixel calculada (x,y) a la trayectoria circular centrada en (xc, yc) 
   y trazamos los valores de las coordenadas: x=x+xc y y=y+yc.
 Fin Para

   Fuente wikipedia.

     Aquí teneis la implementación del algoritmo en ensamblador, comentado en C, para que sirva de entreanmiento a la hora de codificar en lenguaje ensamblador otros algoritmos.




CIRCLE.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 graphics.mac


.model compact,pascal

        public _circle
.data

e dw 0     ;variable p procedimiento breshenham


.code
       ;algoritmo Bresenham
_circle proc uses ax bx dx si di,x0,y0,radio,color
        mov bx,0     ;x=0
        mov dx,radio      ;y=radio
        mov cx,dx   ;e=radio
        neg cx       ;e=-radio
        add cx,1    ; e=1-radio

      
while:        ;while (x<y)
        cmp bx,dx
        jb sig
        jmp fin
sig:
        call _dibuja8   ;dibuja en los 8 octantes
        inc bx       ;x=x+1
        cmp cx,0    ;if (e>0)
        jl else_if
        dec dx       ;y=y+1
        mov ax,bx
        sub ax,dx   ;x-y
        shl ax,1    ;(x-y)*2
        add ax,1  ;1*(x-y)+1
        add cx,ax    ;e=e+ 2*(x-y)+1
        jmp fin_if
else_if:
        mov ax,bx
        shl ax,1
        add ax,1         
        add cx,ax   ;e=e+2*x+1
fin_if:
     
        jmp while      
fin:
        ret
_circle endp 

;dibuja el punto en cada octante, referido a la coordenada origen del circulo
_dibuja8 proc
        mov si,bx          
        add si,x0           ;xc=x+x0
        mov di,dx          
        add di,y0           ;yc=y+y0
        putpixel si,di,color    ;pixel(x+x0,y+y0)
        mov si,dx          
        add si,x0           ;xc=y+x0
        mov di,bx          
        add di,y0           ;yc=x+y0
        putpixel si,di,color    ;pixel(y+x0,x+y0)
        mov si,bx             
        neg si
        add si,x0            ;xc=-x+x0
        mov di,dx          
        add di,y0           ;yc=y+y0
        putpixel si,di,color          ;pixel(-x+x0,y+y0)
        mov si,dx          
        add si,x0           ;xc=y+x0
        mov di,bx             
        neg di
        add di,y0               ;yc=-x+y0
        putpixel si,di,color           ;pixel(y+x0,-x+y0)
        mov si,bx             
        neg si
        add si,x0               ;xc=-x+x0
        mov di,dx 
        neg di              
        add di,y0               ;yc=-y+y0
        putpixel si,di,color          ;pixel(-x+x0,-y+y0)
        mov si,dx 
        neg si              
        add si,x0               ;yc=-y+x0
        mov di,bx             
        neg di
        add di,y0               ;xc=-x+y0
        putpixel si,di,color           ;pixel(-y+x0,-x+y0)
        mov si,bx          
        add si,x0           ;xc=x+x0
        mov di,dx 
        neg di              
        add di,y0               ;yc=-y+y0
        putpixel si,di,color          ;pixel(x+x0,-y+y0)
        mov si,dx 
        neg si              
        add si,x0               ;yc=-y+x0
        mov di,bx          
        add di,y0           ;yc=x+y0
        putpixel si,di,color           ;pixel(-y+x0,x+y0)
        ret
_dibuja8 endp       

end

lunes, 24 de marzo de 2014

ACTUALIZACIÓN LIBRERÍA MATH

   Debido a que ahora vamos a necesitar alguna de las funciones matemáticas publicadas al comienzo del blog, y a que ya nos encontramos programando sobre TASM2.0, voy a refrescar estas librerías, pasando al nuevo fromato de código y comentándolas un poco más.

     Estas librerías son necesarias para realizar el progra,a de ejemplo de circulo que pondré más adelante. Para poder determinar el centro y radio de un circulo a partir de dos pintos elegidos por el ratón en pantalla.
    no pongo todas. Solo las que usaré para realizar un ejemplo como el de dibujos de líneas con el ratón, pero de circulos.
  En este caso, como se trata de refrescar algo que ya he puesto, pondré en unas sola entrada la definición de la cabecera y de cada una de las librerías.

; 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 matemática

MATH.MAC
@b = 2
@o = 8
@d = 10
@h = 16

;valor absoluto del dato 16bits
abs macro dato
local positivo
        add dato,0       
        jns  positivo1    
        neg dato
endm

;suma datos 32bits
suma macro ope1,ope2,res
ifndef _suma
       extrn _suma:near
endif
        lea ax,ope1
        push ax
        lea ax,ope2
        push ax
        lea ax,res
        push ax
        call _suma

     endm
    
;resta datos 32bits    
resta macro ope1,ope2,res
ifndef _resta
       extrn _resta:near
endif
        lea ax,ope1
        push ax
        lea ax,ope2
        push ax
        lea ax,res
        push ax
        call _resta

     endm


;multiplica dato 32 bits
mult macro ope1,ope2,res
ifndef _mult
       extrn _mult:near
endif
        lea ax,ope1
        push ax
        lea ax,ope2
        push ax
        lea ax,res
        push ax
        call _mult

     endm
    
    
;divide dato 32 bits    
divi macro ope1,ope2,res
ifndef _divi
       extrn _divi:near
endif
        lea ax,ope1
        push ax
        lea ax,ope2
        push ax
        lea ax,res
        push ax
        call _divi

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

      endm

;factorial numeros de 32bits
;fac calcula el factorial del int fuente y lo devuelve en destino
fac macro fuente,destino
ifndef _fac
       extrn _fac:near
endif
        lea ax,fuente
        push ax
        lea ax,destino
        push ax
        call _fac

  endm
 
;potencia numeros de 32bits
;fuente es un puntero de una variable de 16 bits
;potencia es una variable de 16 bits
;destino es un puntero a una variable de 32 bits
;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,fuente
        push ax
        mov ax,potenc
        push ax
        lea ax,destino
        push ax
        call _pot

  endm
 
;exp numeros de 32bits 
exp macro potenc,destino
ifndef _exp
       extrn _exp:near
endif
        lea ax,potenc
        push ax
        mov ax,destino
        push ax
        call _exp

  endm

;compara numeros de 32bits
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






Librerías Matemáticas

POT.ASM

; eleva un úmero de 16 bits a otro número dando el resultado en un número de 32 bits
;op1 puntero a varialbe de 16 bits
;op2 numero de 16 bits
;res puntero a variable de 16 bits
model compact,pascal

.code
      public _pot
_pot proc uses bx di cx,op1,op2,res
      extrn _mult:near

 mov cx,op2
        mov bx,op1
        mov di,res
        mov word ptr [di],1
        mov word ptr [di+2],0
 otro:
        cmp cx,0
        jz fin
        push bx
        push bx
        push di
        call _mult
        dec cx
        jmp otro
   fin:
               ret
_pot endp

end


MULT.ASM
;multiplica dos numeros de 32 bits  y el resultado lo lleva a otro de 16 bits
;op1 puntero a nuemro de 32 bits
;op2 puntero a nuemro de 32 bits
;res puntero a número de 32 bits
; multiplica en formato de 32 bits, pero el resultado debe de ser como máximo de 32 bits
;multiplica número sin signo.
.model compact,pascal

.code    
       public _mult
_mult proc uses bx dx cx si di,op1,op2,res
        mov si,op1
        mov bx,op2
        mov di,res
        mov ax,[bx+2]
        push ax
        mov ax,[si]
        push ax
        mov ax,[si]
        mov cx,[bx]
        mul cx
        mov [di],ax
        push dx
        mov ax,[si+2]
        mul cx
        pop dx
        add ax,dx
        mov [di+2],ax
        pop ax
        pop cx
        mul cx
        add [di+2],ax

        ret
_mult endp

end




SUMA.ASM
; codigo
;suma dos números de 32 bits
;sum1 puntero a variable de 32 bits
;sum2 puntero a varialbe de 32 bits
;res puntero a variable de 32 bits
.model compact,pascal
.code
        public _suma
_suma proc uses bx si di,sum1,sum2,res

        mov si,sum1
        mov bx,sum2
        mov di,res
        mov ax,[si]
        add ax,[bx]
        mov [di],ax
        mov ax,[si+2]
        adc ax,[bx+2]
        mov [di+2],ax

        ret
_suma endp

end



SQR.ASM

INCLUDE MATH.MAC
; raiz cuadrada. devuelve en ax el resultado
;Calcula la raiz de un número de 32 bis
; p1 puntero a variable de 32 bits
;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 ^2 - 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)
;SOLO PODREMOS CALCULAR RAICES DE NUMEROS HASTA 4.294.836.225, YA QUE EL RESULTADO DE LA RAIZ LO DEVOLVEREMOS EN AX

model compact,pascal
.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

.code
      public _sqr
_sqr proc uses bx CX si,p1

        mov bx,p1   ;SE RECOGE EL PUNTERO A LA VARIBLE
        mov si,offset N     ; SE ASIGNA SI AL PUNTERO A LA VARIALBE 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
  

        ret
_sqr endp

end



DIVI.ASM
;; solo divide por numeros menores de ffffh
title dividir
include main.mac

.model  compact,pascal
.data 
aux dw 0,0
.code
      public _divi
_divi proc uses bx dx cx si di,dividendo,divisor,resultado

        mov si,dividendo
        mov di,resultado
        mov bx,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:

        ret
_divi endp





RESTA.ASM
; codigo
    public _resta
model compact,pascal

.code
_resta proc uses bx si di,min,subs,res

        mov si,min
        mov bx,subs
        mov di,res
        mov ax,[si]
        sub ax,[bx]
        mov [di],ax
        mov ax,[si+2]
        sbb ax,[bx+2]
        mov [di+2],ax

        ret
_resta endp


end


jueves, 20 de marzo de 2014

FUNCIÓN LINEA



Las dos funciones más importantes gráficas son: el circulo y la recta. A partir  de ellas podremos generar el resto de funciones.
   En las entradas anteriores he colocado la función básica de putpixel, para dibujar un punto, con la cual se podrán generar el resto de las funciones. En este caso he usado, por comodidad la Int 10h de la Bios., pero si alguien quiere puede hacer un putpixel directamente sobre memoria de pantalla. Esta modificación no influirá en el resto de las funciones ya que si se hace el putpixel de forma equivalente, el resto de las funciones seguirán siendo válidas.

    La recta es una función en principio compleja si la queremos hacer sin usar operaciones matemáticas complejas.
     Actualmente, debido a que los ordenadores son potentes, y se trabaja en alto nivel, a cualquiera que se le proponga hacer una recta mediante pixel, utilizará la ecuación de la recta y a correr. Pero si trabajamos en ensamblador, bien sea el que estamos usando, o sea un microcontrolador, de manera que deseemos trazar una línea en un papel mediante motores paso a paso, resulta problemático usar coma flotante.
     En 1965 Bresenham creó unos algoritmos de aproximación para la recta y los círculos, los cuales son capaces de trazar una recta usando solo operaciones incrementales y  operaciones básicas de  ensamblador como multiplica por 2 y sumar.
     Este es el algoritmo que he utilizado en esta función. Este algoritmo es válido solo si la pendiente es mayor de cero y menor de infinito. Es decir no sirve para rectas horizontales y verticales.
   Por lo tanto estos dos casos son tratados de forma independiente.
   Además hay que tratar el caso de trazar la recta en los dos sentidos, para lo cual lo que realizamos es una comprobación del sentido para poner los incrementos (pasox y pasoy) en +1 o -1 según convenga.
   Además el algoritmo solo sirve para un cuadrante, es decir no es lo mismo si la recta aumenta más deprisa en x que en y que si la recta aumenta más deprisa en y que en x. Por ello hay que verificar si Δx> Δy y tomar un algoritmo diferente.

   Como el algoritmo lo podréis encontrar en internet, pero nunca en ensamblador, he decidido hacer un ejercicio de interpretación muy elegante.
    Os he colocado como comentario a la derecha el código equivalente en “C”. Es decir he puesto el código en ensamblador, traduciéndolo a “C”. Esto servirá a muchos para entender el algoritmo, pero a muchos más, para saber cómo codificar en ensamblador  cada directiva de “C”.
    Esto que he hecho, para mi es super sencillo, porque yo comencé con desensamblar y luego pase a “C”, pero me imagino que para los programadores actuales, acostumbrados a lenguajes de alto nivel, es muy difícil hacerse una idea de cómo traducir el “C” a ensamblador.
    En este caso, yo he tomado el algoritmo en “C” y lo he traducido a ensamblador. Esto se puede hacer con cualquier pseudocódigo, por lo que esta entrada es una forma de enseñar este proceso.
   El conjunto de la librería estará formado por una macro, que deberá ser añadida a las cabeceras GRAPHICS.MAC,  que puse antes, y una función, que deberá ser compilada y añadida a la librería mediante TLIB. Así tendremos lista esta función para el futuro. Será usada como una instrucción más, y no tendremos que volver a compilarla, ni a preocuparnos de ella.
   Si se introduce, como yo hago, dentro de una librería, y siempre usamos esa librería, la función será transparente en  nuestras aplicaciones. Podéis ver cómo hacerlo en la pestaña COMPILAR del blog.
    Con esta función podremos realizar el rectangle y el fillrectangle, que pondré en la siguiente entrada.


    Más infornmación sobre el algoritmo  Aquí



GRAPHICS.MAC
;Dibuja una línea
line macro x0,y0,x1,y1,color
ifndef _line
        extrn _line:near
endif
        mov ax,x0
        push ax
        mov ax,y0
        push ax
        mov ax,x1
        push ax
        mov ax,y1
        push ax
        mov ax,color
        push ax
        call _line
       
 endm  





LINEA.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 graphics.mac


.model compact,pascal

        public _line
.data


incE   dw 0
incNE dw 0


deltax dw 0    ;
deltay dw 0

pasox dw 0     ;paso en x
pasoy dw 0     ; paso en y

p dw 0     ;variable p procedimiento breshenham

x0 dw 0    ;parametros pasdados a linea
y0 dw 0    ;usado por todas las rutinas
x1 dw 0
y1 dw 0
color dw 0
.code
       ;algoritmo Bresenham
_line proc uses ax,px0,py0,px1,py1,pcolor
        ;paso de las variables de función a varialbes globales
        ;para uso en todas las rutinas
        mov ax,px0
        mov x0,ax
        mov ax,py0
        mov y0,ax
        mov ax,px1
        mov x1,ax
        mov ax,py1
        mov y1,ax
        mov ax,pcolor
        mov color,ax
       
       ;deltay=abs(yfinal-yinicial)
        mov ax,y1
        sub ax,y0               ; deltay=(y1-y0)
        jns  else_positivo1      ;if (deltay<0)
        neg ax                        ;{abx(deltay)
        mov pasoy,-1                  ;pasoy=-1
        jmp end_positivo1             ;}
else_positivo1:                  ;else
        mov pasoy,1                    ;pasoy=1
end_positivo1:
        mov deltay,ax           ; deltay=abs(y1-y0)
       
        ;deltax=abs(xfinal-xinicial)
        mov ax,x1
        sub ax,x0                ; deltax=(x1-x0)
        jns  elsepositivo2       ;if (deltax>0)
        neg ax                       ;{abx(deltax)
        mov pasox,-1                 ;pasox=-1
        jmp end_positivo2            ;}
elsepositivo2:                    ;else
        mov pasox,1                   ;pasox=1
end_positivo2:

        mov deltax,ax             ; deltax=abs(x1-x0)
        cmp ax,0                  ;if(deltax==0)
        jne no_vertical                  ;{
        call _linea_vertical      ;linea_vertical
        jmp fin_linea                        ;}
no_vertical:

        mov ax,deltay
        cmp ax,0                        ;if(deltay==0)
        jne no_horizontal                   ;{
        call _linea_Horizontal      ;linea_horizontal
        jmp fin_linea                      ;}
no_horizontal:
        
  ;resto de lineas mediante algoritmo Bresenham
        mov ax,deltax
        cmp ax,deltay                    ;if(deltax>deltay)
        jna alg2
        call _algoritmo1    ; algoritmo1
        jmp fin_linea
alg2:                                   ;else
        call _algoritmo2     ;algoritmo2
fin_linea:
        ret
_line endp

_linea_vertical proc uses ax bx cx dx
        mov bx,x0         ; x=x0
        mov dx,y0         ; y=y0
        mov cx,y1         ; yend=y1

while_vert:     
        cmp dx,cx               ;while (y!=yend)
        je fin_vert                  ;{
        putpixel bx,dx,color   ;pixel x,y
        add dx,pasoy                 ;y+=pasoy
        jmp while_vert
       
fin_vert:
        ret
_linea_vertical endp

_linea_horizontal proc uses ax bx cx dx
        mov bx,x0         ; x=x0
        mov dx,y0         ; y=y0
        mov cx,x1         ; xend=x1
      
while_hor:     
        cmp bx,cx               ;while (x!=xend)
        je fin_hor                  ;{
        putpixel bx,dx,color   ;pixel x,y
        add bx,pasox                 ;x+=pasox
        jmp while_hor
       
fin_hor:
        ret
_linea_horizontal endp


 ;si deltax>deltay
_algoritmo1 proc uses ax bx cx dx
        ;p=2*deltay-deltax
        mov ax,deltay         
        shl ax,1     
        mov incE,ax                 ;incE=2*deltay        
        sub ax,deltax          
        mov p,ax                    ;p=2*deltay-deltax 
         
        ;incNE=2*(deltay-deltax)
        mov ax, deltay
        sub ax,deltax
        shl ax,1
        mov incNE,ax                 ;incNE=2*(deltay-deltax)
         

        mov bx,x0         ; x=x0
        mov dx,y0         ; y=y0
        mov cx,x1         ; xend=x1

while1:     
        cmp bx,cx               ;while (x!=xend)
        je fin1                  ;{
        putpixel bx,dx,color   ;pixel x,y
        add bx,pasox                 ;x+=pasox
       
        mov ax,p
        cmp ax,0              ; if(p<0)
        jns else_if1
        add ax,incE
        mov p,ax              ;p+=incE
        jmp short end_if1
else_if1:                     ;else
        add ax,incNE
        mov p,ax             ;p+=incNE
        add dx,pasoy                ;y+=pasoy
end_if1:        
        jmp while1            ;}        
fin1:       
        ret
_algoritmo1 endp

;si deltay>deltax
 _algoritmo2 proc uses ax bx cx dx
        ;p=2*deltax-deltay
        mov ax,deltax         
        shl ax,1   
        mov incE,ax                 ;incE=2*deltay           
        sub ax,deltay          
        mov p,ax                    ;p=2*deltax-deltay 
        
        ;incNE=2*(deltax-deltay)
        mov ax, deltax
        sub ax,deltay
        shl ax,1
        mov incNE,ax                 ;incNE=2*(deltax-deltay)
         

        mov bx,x0         ; x=x0
        mov dx,y0         ; y=y0
        mov cx,y1         ; yend=y1
while2:         
        cmp dx,cx               ;while (y!=yend)
        je fin2                  ;{
        putpixel bx,dx,color   ;pixel x,y
        add dx,pasoy                ;y+=pasoy
       
        mov ax,p
        cmp ax,0              ; if(p<0)
        jns else_if2
        add ax,incE
        mov p,ax              ;p+=incE
        jmp short end_if2
else_if2:                     ;else
        add ax,incNE
        mov p,ax             ;p+=incNE
        add bx,pasox              ;x+=pasox 
end_if2:        
        jmp while2            ;}        
fin2:       
        ret
_algoritmo2 endp
end

viernes, 14 de marzo de 2014

FUNCIONES GRÁFICAS BASICAS

   Algunas de las funciones introducidas en la macro GRAPHICS.MAC serán funciones implementadas mediante rutinas en la librería, bien porque son muy utilizadas y queremos ahorrar algunos bytes frente a las llamadas inline, o bién porque pensamos poder mejorarlas posterioremente sin tener que retocar la llamada.
    Como siempre mi filosofía es crear funciones con el mismo nombre que las macros, pero usando el caracter "_" delante.
    Como ya se ha visto, a mi no me gusta la función "invoke" del ensamblador, ya que impide una visión clara de la secuencia del programa  al llenar de palabras "invoke" el programa. Para entender un programa actual, hay que ir saltandose esta palabra, para llegar a leer el comando.
    Por ello, aunque lleve un poco más de trabajo, yo soy partidario de crear una definición de función, al igual que se haría en "C" en las cabeceres ".h". Esta definición hará la llamada a la función equivalente y nos permitirá trabajar directamente con el nombre de la función y sus parámetros, eliminando el molesto "invoke", que no es mas que un "call".

    Aquí, hoy solo crearé las funciones putpixel y gotoxyG. Como desde hace tiempo, me estoy apoyando en la directiva "use "y "argum". Así no tengo que salvaguardar con push y pop de los registros usados y no tengo que acceder a los parámetros mediante la indexación a través del puntero de pila. Esto desvirtua el verdadero ensamblador, pues hay líneas generadas por el compilador que no están aquí, pero mejora la lectrua del programa.Debemos tener en cuenta, por lo tanto que los programas no contienen todo el código ensamblador.
     Quien quiera conocer como ensambla estas directivas el compilador puede ir a las primeras entradas del blog, donde programo sin usarlas.
    
    Como la pantalla es gráfica, aquí aparece una diferencia, entre las coordenadas de las dos operaciones.
    En putpixel, las coordenadas son las de pantalla 640x480, pero en la función de texto (servicio 2, Int 10), las coordenadas debe de ser las del cursor, que se reducen por 8 en x y por 4 en y. Para no tener que hacer reconversiones en cada caso, las dos funciones trabajan con coordenadas gráficas. La función gotoxyG hace por lo tanto la tansformación de coordenadas gráficas a coordenadas de texto.

     A partir de ahora y progresivamente iré ampliando esta libería con el resto de las funciones gráficas, colocando un ejemplo ejecuable por cada nueva función, hasta poder realizar un pequeño juego gráfico, integramente hecho en ensamblador, al igual que he ido haciendo con los programas en pantallas de texto.

GRAPHICS.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/>.



    public _gotoxyG
    public _putpixel
.286   
.model compact,pascal
.code
proc _putpixel uses ax cx dx bx,x,y,color:byte
        mov cx, x
        mov dx, y                      ; (CX,DX) = (x,y)
        xor bh, bh                       ; p gina 0
        mov al, color                  ; AL = Color del pixel      
        mov ah, 0Ch                    ; AH = 0x0C (WritePixel)
        int  10h 
        ret
_putpixel endp

end
;coloca el cursor en la posición indicada  en una pnatalla gráfica
proc _gotoxyG uses ax dx cx bx,x,y
        mov bh,0
        mov ax,x
        shr ax,3
        mov dl,al
        mov ax,y
        shr ax,4
        mov dh,al
        mov ah,02h
        int 10h
        ret
_gotoxyG endp  

viernes, 7 de marzo de 2014

ITOA

   Como un lector me planteó este problema, que ya tenía resuelto y me pasó su versión de la rutina para 32bits. He decidido volver a hacer una entrada con el proceso.
   Esta vez lo colocaré para TASM2.0, usando las directivas uses y argum. Aunque lo seguiré colocando en 16bits, ya que para 32 es idéntico. cambiando SI por ESI, DI por EDI etc y realizando la división en un solo paso (cambiando AX por EAX) , a no ser que se quiera hacer con números de 64 bits en cuyo caso la rutina quedaría igual que la actual, cambiando todos los registros a los extendidos.

En la versión puesta usámos procesador de 16 bits y interpretamos números de 32 bits:
        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


Si usásemos procesador de  32 bits y interpretamos números de 32 bits:
       mov ax,[esi]    ;toma la parte alta del número
       xor edx,edx             ;borra el resto
        div cx                ;divide por la base
        mov [esi],eax         ; almacena el resultado
         mov bl,dl           ;toma el resto en bl, para indexar el caraceter


Si usásemos procesador de  32 bits y interpretamos números de 64 bits:

        mov eax,[esi+4]    ;toma la parte alta del número
        xor dx,dx             ;borra el resto
        div cx                ;divide por la base
        mov [si+4]e,ax         ; almacena el resultado
        mov eax,[esi]        ;toma la parte baja
        div cx               ; divide por la base
        mov [esi],eax          ;almacena el resultado
        mov bl,dl           ;toma el resto en bl, para indexar el caraceter


El resto del paso a 32bits queda para el lector, ya que es muy sencillo.




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/>.

        public _itoa


.model compact,pascal

.data

caracteres db "0123456789ABCDEF"
numero dd 0
puntero dw 0
.code

proc _itoa uses bx cx dx si di,dest,dato,base
        mov cx,base       ;recogida del parámetro base a la que se convertirá
        mov bx,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,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 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
        mov puntero,di               ; almacena el puntero para el inicio la posterior formación del número

  posit:
        xor bh,bh     ;inicia bh
        xor di,di    ;inica cuenta de caracteres , uso ahora di como contador
  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
        ret
_itoa endp

end



lunes, 2 de diciembre de 2013

LIBRERÍA 48IOCENT

   
   Ya estamos listos para crear las funciones de control de la tarjera de 48 E/S. Esta librería la asociaremos a la general o crearemos una nueva para  nuestro hard.


    Dado que las funciones van asociadas al puerto paralelo, y dado que solo existe uno normalmente en los ordenadores, no defino dos puertos y trabajo directamente con el lpt1. Por eso en el programa trabajo directamente con las direcciones del puerto centronics, ya que crear variables y asignarlas a diferentes direcciones, creo que resulta un trabajo innecesario, dado el uso que haremos de las funciones.

    
48IOCENT.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/


;CONTROL DE ACCIONES SOBRE LOS 8255
;ESTAS VARIABLES MUEVEN ELAS SEÑALES DE CONTROL
;DE LOS BUFER Y LATCH DE LA TARJETA PARA ABRIR
;PASO A LOS DATOS DENTRO ENTRE EL CENTRONICS Y
;LOS PUERTOS DE LOS 8255
RDL   EQU 0010b     ;LECTURA DE NIBLE BAJO
RDH   EQU 0100B     ;LECTURA DEL NIBLE ALTO
WR    EQU 0001B     ;ESCRITURA
ENDIR EQU 1000B     ;DIRECCIONAMIENTO

.model compact,pascal
.code
        public _inpio
        public _outpio
;lee un dato del puero 8255 indicado y lo devuelve en al
_inpio proc near uses bx cx dx,PUERTO
      
        push PUERTO             ;Selecciona el puerto indicado
        call _selecreg
        add sp,2
        mov al,RDH               ;Activa la orden RDh lectura parte alta
        out dx,al
        mov bx,379h
        xchg bx,dx
        in al,dx                ;lee el pueto 379h
        shl al,1                ; sube 1 bit lo leido para dejarlo como parte
        and al,0f0h
        mov ch,al               ;alta
        xchg bx,dx
        mov al,RDL              ;activa la orden RDl lectura parte baja
        out dx,al
        xchg bx,dx
        in al,dx                ;lee el puerto 379h y toma la parte baja
        mov bl,al
        mov cl,3
        shr bl,cl               ;traslada los bit abajo para posicionarlos
        and bl,0fh              ;elimina la posible basura
        or ch,bl                ;une lo leido a lo leido anteriormente
        mov al,ch               ;pasa el resulatado a al
        ret
_inpio endp

 ;envío  un dato del puero 8255 indicado
_outpio proc near   uses bx cx dx,PUERTO,DATO:byte

        push PUERTO             ;Selecciona el puerto indicado
        call _selecreg
        add sp,2
        mov dx,378h             ;lanzo el numero
        mov al,DATO
        out dx,al
        mov dx,37ah
        mov al,WR               ;indico WR
        out dx,al
        xor al,al               ;desactivo WR
        out dx,al

        ret
_outpio endp

        
;selecciona un registro interno de la targeta
; ESTA FUNCIÓN ES INTERNA A ESTA LIBRERÍA Y PERMITE
; ESCRIBIR LA DICRECIÓN DEL PUERTO ACTIVADA, PARA QUE
; SE GUARDE EN EL REGISTRO DE DIRECCIONES
; INTERNO DE LA TARJETA 48IOCENT
_selecreg proc near uses dx bx,puerto:byte    ;registro indicado en pila

        mov dx,37ah     ;elijo puerto de control del centronics
        mov al,ENDIR
        out dx,al        ;activo lach de direccion y desactivo resto
        mov bx,378h
        xchg bx,dx
        mov al,puerto
        out dx,al        ;lanzo la direccion indicada
        xchg dx,bx
        xor al,al
        out dx,al       ;deselecciono el lach de direccion

        ret
_selecreg endp

end