Vistas de página en total

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

miércoles, 12 de marzo de 2014

GRAFICOS

    Con las funciones que ya he implementado en el blog, se puede hacer prácticamente de todo en modo texto, llegando sin problema, como he mostrado en los ejemplos a mover todo tipo de datos. ¿ Pero qué falta.?
     Claramente faltan los gráficos. A partir de ahora iré añadiendo funciones para resolver los gráficos.
  Hay muchos modos de pantalla, y deberíamos de resolver de forma inicial la detección de la tarjeta gráfica y del modo más alto posible. pero como eso hará que no se vean resultados de forma inmediata, y como yo se que la mejor manera de picar a alguien en este mundo es hacer que funcione, comenzaré como siempre con cosas sencillas que funcionen.
   No es el fin de este blog crear un entorno de programación profesional, para eso ya están las librerías del MASM 32. El fin es mostrar recursos para hacer nosotros mismos las cosas. Para aprender desde cero. Si sabemos hacerlo nosotros mismos todo, será muy fácil entender lo que nos muestren los demás y adaptarlo a nuestro modo de programación.
   Aunque sea de forma muy sencilla se pueden hacer, para enseñanza, grandes programas y elegantes.
   En este caso vamos a usar siempre el modo 12H de video. Es un modo de 640x480 pixel y 16 colores. no son muchos colores para hacer un juego, ni mucha resolución, pero es un modo compatible con todos las tarjetas, pues es uno de los modos EGA primeros que se produjeron. Antes incluso de que existiese las VGA. Por lo tanto es compatible totalmente. Luego Si alguien quiere, que implemente en la rutina de selección de modo gráfico que yo pongo una versión que rastree la memoria de tarjeta y seleccione el modo más adecuada entre los que soporte.
    Para ello disponéis de esta página donde se explica muy bién como obtener esta información.
Modos gráficos
      
    Como siempre comienzo con una cabecera de macros para llamar a las funciones principales.
   En ella faltan macros para las funciones más complejas. Estas las iré colocando según vaya colocando las funciones. Para empezar colocaré las funciones más básicas.
    Lo más básico es:
·         Elegir el modo gráfico.
·         Pintar un pixel.
·         Imprimir una letra
·         Situar el cursor en la pantalla gráfica
  Con estas funciones podremos realizar dos pequeños programas.
      Uno presentará en pantalla la letra que indiquemos por teclado situándola donde pulsemos el ratón.
      El otro será el inicio de un Paint. Dibujará lo que hagamos con el ratón cuando pulsemos el botón izquierdo.
     Por lo tanto en la siguiente entrada pondré las funciones a añadir a la librería, asociada a las macros.
    Y en las dos entradas siguientes los dos programas dichos anteriormente.
    Hay que tener en cuenta que estamos trabajando en DOS. Y por lo tanto no usamos las API’s de Windows. Somos autónomos. Solo usamos las interrupciones de la BIOS, en este caso. Por ello para correr estos programas en Windows7 hace falta un emulador de DOS como el DOSBOX.








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


;MODOS DE PANTALLA
t40mon equ 0
t40col equ 1
t80mon equ 2
t80col equ 3
cga320x200 equ 4
cga640x200 equ 6
ega320x200 equ 13h
ega640x350 equ 10h
ega640x480 equ 12h      ;16 colores
VGA640x480 equ 2AH      ;256 colores



; Presenta un pixel en pantalla Gráfica en el color establecido
putpixel macro x,y,color
ifndef _putpixel
        extrn _putpixel:near
endif
        mov ax,x
        push ax      
        mov ax,y
        push ax
        mov ax,color
        push ax
        call _putpixel
 endm

;Presenta un caracter en modo gráfico en la posición actual del cursor
putcharG macro dato
         push cx

        push bx
        mov ah,0Ah
        mov al,dato
        mov bh,0
        mov cx,1
        int 10h
        pop bx
        pop cx
endm 



;selecciona el modo de video
 modovideo macro modo
        mov ax,modo
        int 10h
        endm



;posicionador de cursor en coordenadas gráficas

gotoxyG macro x,y
ifndef _putpixel
        extrn _gotoxyG:near
endif
        mov ax,x
        push ax
        mov ax,y
        push ax
        call _setcursorG
       
 endm   

jueves, 12 de diciembre de 2013

LIBRERÍA EMULADOR 8051

   Librería de funciones básicas de control de la targeta  8051 del emulador.



EMU8051.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 io.mac
include 48iocent.mac
include 8051.mac

PASO EQU 1

        public _Dma_on
        public _Dma_off
        public _lee
        public _reset
        public _trace

        public _Guarda
        public _Toma  
       
        extrn des_base:word
        extrn Dir_cur:word
        extrn CONTROL:word
   
.model compact,pascal


.data
dir dw 0
paro db "Microprocesador Parado",0
.code

_Dma_on proc near
        pioconfig p0,PSALIDA
        ret
_Dma_on endp

_Dma_off proc near
        pioconfig P1,PA PB PCL PCH
        pioconfig P0,PSALIDA
        outpio p0,BUSRQPC_ON
        ret
_Dma_off endp


;lectura zona programa
_leeinst proc uses bx cx dx
        Dma_on
        pioconfig P1,PCL
        outpio P1,WR_ON
        outpio P1,RD_ON
        outpio P1,ALE_ON
        outpio P1,PSEN_ON
        outpio PA1,dl
        pioconfig P1,PA PCL
        outpio PB1,dh
        outpio P1,WR_ON
        outpio P1,RD_ON
        outpio P1,PSEN_OFF   ;LA LECTURA SE HACE CON RD=1 Y PSEN=0 POR SER PROGRAMA
        inpio al,PA1
        push ax
        outpio P1,RD_ON
        Dma_off
        pop ax

        ret
_leeinst endp

;lectura un dato de  area de datos
;dir =dirección de lectura en ram del prototipo
;devuelve el dato en al
_lee proc near uses bx cx dx,dir
        mov dx,dir
        Dma_on
        pioconfig P1,PCL
        outpio P1,WR_ON
        outpio P1,RD_ON   ;PSEN=1 POR SER LECTURA DE DATOS
        outpio P1,ALE_ON
        outpio P1,PSEN_ON
        outpio PA1,dl
        pioconfig P1,PA PCL
        outpio PB1,dh
        outpio P1,WR_ON
        outpio P1,PSEN_ON
        inpio al,PA1
        push ax
        outpio P1,RD_ON
        Dma_off
        pop ax
        ret
_lee endp


;Guarda de zona de datos
; dir =dirección de volcado en ram del prototipo
; dirección =puntero a los datos a volcar
; long =cantidad de datos
_Guarda proc uses bx dx,dir,dato,long
        mov dx,dir
        mov bx,dato
        mov cx,long
        Dma_on
        pioconfig P1,PCL
        outpio P1,WR_ON
        outpio P1,RD_ON   ;PSEN=1 POR SER LECTURA DE DATOS
        outpio P1,PSEN_ON
Guard:
        outpio P1,ALE_ON
        outpio PA1,dl
        outpio PB1,dh
        outpio P1,ALE_OFF
        outpio PA1,[bx]
        outpio P1,WR_OFF
        outpio P1,WR_ON
        inc bx
        inc dx
        loop guard
        Dma_off
        ret
_guarda endp

;toma una zona de datos
 ;lee una zona de memoria
; dir =dirección de volcado en ram del prototipo
; dirección =puntero a los datos a volcar
; long =cantidad de datos
_Toma proc uses bx dx,dir,datos,long
        mov dx,dir
        mov bx,dato
        mov cx,long
        Dma_on
Tom:
        lee dx,bx,cx
        mov [bx],al
        inc bx
        inc dx
        loop Tom
        Dma_off
        ret
_Toma endp

;ejecuta una instruciión
;en pulsos se pasará el numero de pulsos de reloj de la instrucción

_trace proc uses cx dx, pulsos
        pioconfig P1,PCL
        outpio P1,WR_ON
        outpio P1,RD_ON   ;PSEN=1 POR SER LECTURA DE DATOS
        outpio P1,PSEN_ON
        outpio P1,ALE_ON
        mov dx,Dir_cur
        outpio PA1,dl
        outpio P1,ALE_OFF
        Dma_off
        mov cx,pulsos
        dec cx
buc:
        outpio P0,CLK_ON
        outpio P0,CLK_OFF
        loop buc
busca_ale:
        inpio dl,PC1
        test dl,ALE
        jnz falta
        test dl,PSEN
        jnz final
falta:
        inpio dl,PA1
        inpio dh,PB1
        mov Dir,dx
        outpio P0,CLK_ON
        outpio P0,CLK_OFF
        jmp short busca_ale
final:  mov dx,dir
        mov Dir_cur,dx
        and CONTROL, not PASO
        ret
_trace endp

  ;resetea el programa
_reset proc uses cx
        mov Dir_cur,0
        pioconfig P0,PA PB
        outpio P0,EXTERNO_OFF
        outpio p0,BUSRQPC_ON
        pioconfig P1,PA PB PCH
        outpio P1,RESET_ON
        outpio P1,INT0_ON
        outpio P1,INT1_ON
        mov cx,12
bucr:
        outpio P0,CLK_ON
        outpio P0,CLK_OFF
        loop bucr
        outpio P1,RESET_OFF
        mov cx,12
        call _trace
        pioconfig P1,PA PB PCH PCL
        mov des_base,0
        ret
_reset endp

     end

domingo, 8 de diciembre de 2013

Concatenar un número indeterminado de cadenas

Como respuesta a una pregunta de un lector del blog, voy a añadir esta entrada.

   Si no me equivoco al interpretar su pregunta, el problema que se quiere es poder concatenar dos o más cadenas en una destino.
   Para hacerlo de forma elegante, voy a crear una macro.
    Esta macro va a concatenar las cadenas mediante llamadas consecutivas a la función strcat.
    La ventaja de la macro es que podemos añadir la llamada adicional solo si se pasa como parámetro el puntero a una nueva cadena, de forma que podemos dejar definida la función para un número indeterminado de cadenas. En este caso lo haré de 2 hasta 7.

   Para ello vamos a usar la función strcat para unir las dos primeras cadenas a la tercera. Luego, cuando exista el siguiente parámetro, tomaremos la dirección del destino, calcularemos su longitud y la sumaremos a su dirección de puntero. Así crearemos un puntero al final de la cadena destino. Esto lo haré en SI, para poder direccionarlo como [si] y pasarlo como parámetro a la macro strcpy. Así con esa nueva dirección puedo llamar de nuevo a strcpy y acoplar la cadena a la que ya existía.
    También lo podía haber hecho mediante sucesivas llamadas a strcat destino,destino,fuente?, pero de esta segunda forma perdería tiempo en copiar muchas veces la misma cadena.

    Si llamo a la macro
            Add_str destino,fuente1,fuente2  ;copia dos cadenas en destino
            Add_str destino,fuente1,fuente2,fuente3   ;copia tres cadenas en destino
        etc

    Add_Str macro destino,fuente1,fuente2,fuente3,fuente4,fuente5,fuente6,fuente7
               strcat destino,fuente1,fuente2      ;primera llamada con el mínimo permitido
            push si
           ifnb <fuente3>
               strlen destino
               lea si,destino
               add si,ax
               strcpy [si],fuente3      ;primera llamada
           else
                 ifnb <fuente4>
                     strlen destino
                      lea si,destino
                      add si,ax
                      strcpy [si],fuente4      ;segunda llamada
                  else
                      ifnb <fuente5>
                           strlen destino
                             lea si,destino
                             add si,ax
                            strcpy [si],fuente5      ;tercera llamada
                      else
                            ifnb <fuente6>
                                strlen destino
                                 lea si,destino
                                add si,ax
                                strcpy [si],fuente6      ;cuarta llamada
                             else
                                 ifnb <fuente7>
                                     strlen destino
                                     lea si,destino
                                    add si,ax
                                    strcpy [si],fuente7      ;quinta llamada
                                 endif
                            endif
                     enidf
              endif
         endif
         pop si
endm

  Realmente lo he creado como una nueva función, pero podría haber ampliado simplemente las que ya tenía publicadas en la cabecera string.mac.
   Por ejemplo, podríamos haberla llamado strcat directamente, pues en su modo más corto llama directamente a esa función. 

    Hay que tener en cuenta que el enlace está enviado a una versión inicial de las macros. En ella no usábamos el comando USE del TASM 2.0.
   Para pasar al modo de programación actual, en el que si usamos ya el comando USE del TASM2.0 habrá que aplicar la conversión indicada en la entrada del blog "pasamos a integrar TASM2.0"
   Con esta salvedad, colocaré ahora una versión actualizada de strcat y otra de strcpy, que podrán hacer la misma función que la anterior.

    Si en vez de crear una función nueva ampliamos strcat para que tenga polimorfismo, quedará:

strcat macro destino,fuente1,fuente2,fuente3,fuente4,fuente5,fuente6,fuente7
 ifndef _strcat
      extrn _strcat:near
 endif
        lea ax,destino
        push ax
       lea ax,fuente1
        push ax
        lea ax,fuente2
        push ax
        call _strcat                ;primera llamada. Sumamos fuente1, y fuente2 en destino
  
; a partir de ahí todo es igual    
        push si
           ifnb <fuente3>
               strlen destino
               lea si,destino
               add si,ax
               strcpy [si],fuente3      ;primera llamada
           else
                 ifnb <fuente4>
                     strlen destino
                      lea si,destino
                      add si,ax
                      strcpy [si],fuente4      ;segunda llamada
                  else
                      ifnb <fuente5>
                           strlen destino
                             lea si,destino
                             add si,ax
                            strcpy [si],fuente5      ;tercera llamada
                      else
                            ifnb <fuente6>
                                strlen destino
                                 lea si,destino
                                add si,ax
                                strcpy [si],fuente6      ;cuarta llamada
                             else
                                 ifnb <fuente7>
                                     strlen destino
                                     lea si,destino
                                    add si,ax
                                    strcpy [si],fuente7      ;quinta llamada
                                 endif
                            endif
                     enidf
              endif
         endif
         pop si 

  endm

    El ahorro es simplemente tener una sola función que vale para todo, ya que no tiene sentido strcat si Add_Str hace lo mismo.
 
     Pero claro, igualmente podríamos pensar con strcpy. Dado que strcat no es mas que dos llamadas a strcpy, podríamos construir strcat mediante strcpy, y si hacemos polimorfismo, nos bastará con strcpy, para realizar todas las posibilidades.

      ¿Que Sacrificamos?
      Sacrificamos código. Si usamos macro, cada llamada consumirá más código, que si usamos la llamada a la función strcat. Es por eso que cree strcat. Sin embargo, Add_Str si interesa hacerlo en macro, ya que concatenar  más de una cadena a la vez es más raro, y tener una función que no se usa, también puede aumentar el código, al incorporar librerías innecesarias.

    De todas formas vamos a ver como crear un strcpy,que sirva para todo.

strcpy macro destino,fuente1,fuente2,fuente3,fuente4,fuente5,fuente6,fuente7
ifndef _strcpy
    extrn _strcpy:near
endif
        lea ax,destino
        push ax
        lea ax,fuente1    ;copia inicial
        push ax
        call _strcpy
; a partir de ahí todo es igual , pero con una llamada más
        push si
           ifnb <fuente2>
               strlen destino
               lea si,destino
               add si,ax
               strcpy [si],fuente2      ;primera llamada
           else
                 ifnb <fuente3>
                     strlen destino
                      lea si,destino
                      add si,ax
                      strcpy [si],fuente3     ;segunda llamada
                  else
                      ifnb <fuente4>
                           strlen destino
                             lea si,destino
                             add si,ax
                            strcpy [si],fuente4      ;tercera llamada
                      else
                            ifnb <fuente5>
                                strlen destino
                                 lea si,destino
                                add si,ax
                                strcpy [si],fuente5      ;cuarta llamada
                             else
                                 ifnb <fuente6>
                                     strlen destino
                                     lea si,destino
                                    add si,ax
                                    strcpy [si],fuente6       ;quinta llamada
                                 else
                                    ifnb <fuente7>
                                         strlen destino
                                         lea si,destino
                                         add si,ax
                                         strcpy [si],fuente7       ;quinta llamada

                                    endif
                                 endif
                            endif
                     enidf
              endif
         endif
         pop si 
 endm

    Como se ve, hará lo mismo, y podrá usarse tanto para copiar una cadena, como para acoplar de 2 a 7 cadenas.
    Pero claro, para sumar dos cadenas perderemos más espacio si lo usamos varias veces, frente a usar strcat.

CABECERA EMULADOR 8051

    Vamos a empezar con el programa de control para el emulador 8051, definiendo la cabera para sus funciones básicas de control.
      En este caso lo primero será definir las señales de control y las funciones básicas de lectura, escritura y manejo de la memoria a través del DMA. Así mismo añado en esta cabecera la función Trace para controlar el reloj y ejecutar una instrucción.
   
EMU5051.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/

;identificacion señales
;PC1 -  PUERTO "C" ALTO DE LA TARJETA 48IOCENT
INT0 EQU 1    ;SEÑAL DE INTERRUPCIÓN 1
INT1 EQU 2    ;SEÑAL DE INTERRUPCIÓN 2
RESET EQU 4   ; RESET
WR EQU 20h     ; SEÑAL DE ESCRITURA
RD EQU 10h    ;SEÑAL DE LECTURA
PSEN EQU 40h    ; SEÑAL PSEN
ALE EQU 80h     ;SEÑAL Ale


;salidas control 
;PC0 . PUERTO "C" BAJO DEL LA TARJETA 48IOCENT
CLK_ON EQU 11B    ; ACTIVAR SEÑAL DE RELOJ 
CLK_OFF EQU 10B    ; DESACTIVAR SEÑAL DE RELOJ
BUSRQPC_ON EQU 01B  ; ACTIVAR SOLICITUD DE BUS
BUSRQPC_OFF EQU 00B  ;DESCTIVAR SEÑAL DE RELOJ
EXTERNO_ON EQU 101B   ;ACTIVAR BUS EXTERNO
EXTERNO_OFF EQU 100B   ;DESCTIVAR BUS EXTERNO

;control PC1
PSEN_ON EQU 1101B    ;ACTIVAR PSEN
PSEN_OFF EQU 1100B   ;DESACTIVAR PSEN
ALE_ON EQU 1111B      ;ACTIVAR ALE
ALE_OFF EQU 1110B    ;DESACTIVAR ALE


WR_ON EQU 1011B    ;ACTIVAR WR
WR_OFF EQU 1010B ; DESCTIVAR WR
RD_ON EQU 1001B  ; ACTIVAR RD
RD_OFF EQU 1000B   ;DESACTIVAR RD
RESET_ON EQU 101B   ; ACTIVA RESET
RESET_OFF EQU 100B   ;DESACTIVAR OFF
INT1_ON EQU 11B   ; ACTIVAR INT1
INT1_OFF EQU 10B   ; DESACTIVAR INT1
INT0_ON EQU 1    ; ACTIVAR INT0
INT0_OFF EQU 0   ; DESACTIVAR INT0


;MACROS de control de tarjeta
;activa DMA
Dma_on macro
ifndef _Dma_on
     extrn _Dma_on:near
endif
    call _dma_on   
endm

;desactiva DMA
Dma_Off macro
ifndef _Dma_off
     extrn _Dma_off:near
endif
    call _dma_off   
endm

;Lee de zona de programa
LeeInst macro 
ifndef _LeeInst
     extrn _LeeInst:near
endif
    call _LeeInst
endm

;Lee de zona de datos
;lectura un dato de  area de datos
;dir =dirección de lectura en ram del prototipo
;devuelve el dato en al
Lee macro dir
ifndef _Lee
     extrn _Lee:near
endif
    lea ax,dir
    push ax
    call _Lee
endm

;Guarda de zona de datos
; dir =dirección de volcado en ram del prototipo
; dirección =puntero a los datos a volcar
; long =cantidad de datos
Guarda macro dir,datos,long
ifndef _Guarda
     extrn _Guarda:near
endif
    mov ax,dir
    push ax
    lea ax, datos
    push ax
    mov ax,long
    push ax
    call _Guarda
endm

;lee una zona de memoria
; dir =dirección de volcado en ram del prototipo
; dirección =puntero a los datos a volcar
; long =cantidad de datos
Toma macro dir
ifndef _Toma  dir,datos,long
     extrn _Toma:near
endif
    mov ax,dir
    push ax
    lea ax, dato
    push ax
        mov ax,long
    push ax
    call _Toma 
endm


;tracea una instrución. 
;En el parámetro se le pasa el número de pulsos  de la instruciión
Trace macro pulsos
ifndef _Trace
     extrn _Trace:near
endif
    mov ax,pulsos 
    pusxh ax
    call _Trace  
endm


viernes, 29 de noviembre de 2013

CABECERA 48IOCENT

   Una vez que tenemos la tarjeta de E/S lista y hemos probado que llegan todas las señales correctamente y funcionan todas sus puertas, podemos comenzar a realizar el driver, o la librería para su control directo.
   Con esta librería podremos manejar ya sus puertos de forma transparente y configurar de forma sencilla la tarjeta.

    Para ello, como siempre, primero crearemos la cabecera con las constantes de control y configuración y las funciones de llamada.

    Para manejar los puertos de esta tarjeta necesitaremos:
                         Una función de configuración de tarjeta que llamaremos PioConfig.
                         Una función de envío a puerto que llamaremos OutPio.
                         Una función de lectura de puerto que llamaremos InPio.



    Aquí pongo la definición de la cabecera. En la siguiente entrada pondré la definición de las funciones que aquí llamo.



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/

;DIRECCIONAMENTO DE PUERTOS DE LA TARJETA 48IOCENT
;USART 1
PA0 EQU 0
PB0 EQU 1
PC0 EQU 2
P0 EQU 3        ;REGISTRO DE CONTROL
;USART 2
PA1 EQU 4
PB1 EQU 5
PC1 EQU 6
P1 EQU 7        ;REGISTRO DE CONTROL

;CONFIGURACIONES DE LOS PUERTOS
PSALIDA EQU 80H
PA EQU  10010000B
PB EQU  10000010B
PCH EQU 10001000B
PCL EQU 10000001B

;lee un dato del puero 8255 indicado y lo devuelve en al o en la variable indicada
InPio macro dest,puerto
ifndef _inpio
        extrn _inpio:near
endif
        mov ax,puerto
        push ax
        call _inpio
ifdif <reg>,<al>
        mov dest,al
endif
endm

;envío  un dato del puero 8255 indicado
OutPio macro puerto,dato
ifndef _outpio
        extrn _outpio:near
endif

        mov ax,puerto
        push ax
        mov al,dato
        push ax
        call _outpio

 endm

;CONFIGURA UN PUERTO 8255 DE LA TARJETA
 ;PARA DEFINIR LOS MODOS DE FUNCIONAMIENTO DE LOS PUERTOS BASTARA
;INDICAR LOS QUE SEAN DE ENTRADA, LOS DEMAS SERAN DE SALIDA
;ASI PA-I PB-O PCH-I SE INDICARA COMO.. "PA" OR "PCH"
;EN EL CASO DE TODO COMO SALIDA SE INDICARA "PSALIDA"
; PIOCONFIG P0,PA,PB ESTO CONFIGURARIA EL 8255 0 CON LOS PUERTOS
; A Y B COMO ENTRADA
; el puerto C podrá ser definido por nible como entrada o salida
PioConfig macro pio,cnfg0,cnfg1,cnfg2,cnfg3
ifndef _outpio
        extrn _outpio:near
endif
        mov ax,pio
        push ax
ifnb <cnfg3>
        mov al,cnfg0 or cnfg1 or cnfg2 or cnfg3
else
  ifnb <cnfg2>
        mov al,cnfg0 or cnfg1 or cnfg2
else
  ifnb <cnfg1>
        mov al,cnfg0 or cnfg1
else
        mov al,cnfg0
endif
endif
endif
        push ax
        call _outpio
endm

 

viernes, 15 de noviembre de 2013

Protocolo DH+ Network

    Debido a mi formación trabajo con  automática y a la necesidad de comunicar con autómatas concretos, el protocolo que implementé inicialmente para mis comunicaciones fue del DH+ de Allen- Bradley. Como este fue el primero que implementé, fue el que luego utilicé para mis desarrollos y el que ahora pongo.

    Es por esto, que cuando tuve que hacer cualquier comunicación entre robots y autómatas, robots y ordenadores, o ordenadores y placas con  procesadores, siempre usé este.
  
    Como no se trata de un protocolo x-modem literal, pongo un enlace en el que se explica este protocolo.
    En las librerías incorporo hasta el nivel de enlace al nivel de transporte. El resto de niveles, aunque se explican en el enlace para Allen-Bradeley, no los implementaré, pues se trata de ordenes específicas. Cada uno podrá usar los comandos que desee comunicar con sus tarjetas o equipos.




Comenzaré por lo tanto por colocar como siempre la cabecera para la llamada a las funciones.


DH.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 PROTOCOLO  Data Highway II (DH+) network

include rs232.mac

;caracteres de comunicacion
SOH EQU 1      ;ENCABEZAMIENTO
STX EQU 2      ;COMIENZO TEXTO
ETB EQU 17H    ;FINAL BLOQUE (QUEDAN MAS)
ETX EQU 3      ;FINAL DE MENSAJE
ACK EQU 6      ;RECONOCIMEINTO
NACK EQU 15H   ;NO RECONOCIDO
DLE EQU 10H    ;CONTROL
ENQ EQU 5      ;SOLICITUD DE RESPUESTA
EOT EQU 4      ;FIN TRANSMISION
SYN EQU 16H    ;ESPERA SINCRONICA
CAN EQU 1BH    ;CANCELAR, ESC

; envía una cadena de datos por puerto serie mediante
; protocolo DH+
Send_DH macro nodo,datos,longitud
ifndef _Send_DH
    extrn _Send_DH:near
endif
        mov ax,nodo
        push ax
        lea ax,datos
        push ax
        mov ax,longitud
        push ax
        call _Send_DH
       
 endm

; recibe una cadena de datos por puerto serie mediante
; protocolo DH+
; devuelve en el mensaje en el buffer  datos
; dh= logitud del mensaje
; dl= nodo;   el nodo que lo envía en dl   0-255
; al=estado   Si al=0ffh error, al=0 ok
Recive_DH macro datos
ifndef _Recive_DH
    extrn _Recive_DH:near
endif
        lea ax,datos
        push ax
        call _Recive_DH
   
 endm
 

miércoles, 13 de noviembre de 2013

COMUNICACIÓN RS232

 Hoy vamos a comenzar con los puertos de comunicación, y en particular con el puerto serie.
 No vamos a usar interrupciones, ni el dos. Vamos a programar el PIO directamente.
 Para ello usaremos las nuevas funciones de la entrada anterior peek y poke.

     Con esta cabecera rearemos unas funciones básicas para inicialización, lectura y escritura sobre el PIO 8050, que nos permitirán leer y escribir sobre el puerto serie. Se pueden  ampliar después convirtiéndolas en funciones, con gestión de errores, pero como la idea de este blog es estar al menor nivel, pero que sea operativo, lo dejaré así.
    La idea del blog, como dije desde el principio es que sea didáctico a bajo nivel, pero permitiendo al mismo tiempo hacer operativo el ensamblador.
     Ya sabemos que se puede hacer mejor... pero para hacerlo mejor usaríamos las librerías ya existentes. Sin embargo los ejemplos que existen a bajo nivel no son realmente operativos sin un debuger, pues les falta implementación.

     Como ya habréis visto es blog es algo intermedio, estando siempre en bajo nivel, como si el PC fuera un microordenador, estamos haciendo programas útiles y ejecutables por si solos, sin necesidad de debuger, para ver los resultados.

   

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

include io.mac

;CABECERA Y MACROS COMUNICACIÓN SERIE

;velocidades de transmisión
v4800 equ 24
V9600 EQU 12
V19200 EQU 6

;direcciones PUERTO COM 1
rtd equ 3f8h  ; Transmitter Holding Register
lsb equ 3f8h  ; Receiver Data Register SI BIT 7=0 EN LC, Baud Rate Divisor SI BIT 7=1 EN LC
msb equ 3f9h  ;Baud Rate Divisor    SI bit 7=1 LC
ie equ  3f9h  ;Interrupt Enable Register
ii equ  3fah  ;Interrupt Identification  Register
lc equ  3fbh  ;Line Control Register   
mc equ  3fch   ;Modem Control Register
ls equ  3fdh   ;Line Status Register   
ms equ  3feh   ;Modem Status  Register




; LECTURA DE CARACTER POR PUETO SERIE
getcaux macro
local rs_bien
local espera1
espera1:
        peek ls      ;LECTURA REGISTRO DE ESTADO
        test al,1eh  ; VERIFICACIÓN DE ERRORES          
        jz rs_bien    ;SI NO HAY ERROR SEGUIMOS
        peek rtd      ;TOMAMOS EL ERROR.. nO VAMOS A TRATARLO RODAVÍA. AQUÍ PODRÍAMOS TRATARLO MEDIANTE UN MENSAJE
rs_bien:
        test al,1     ; VERIFICAMOS SI HAY DATO
        jz espera1    ; ESPERAMOS RECIBIRLO
        peek rtd       ; LO LEEMOS
        endm

;ENVÍO DE CARACTER POR PUERTO SERIE
putcaux macro dato
local espera
espera: peek ls            ; SE LEE EL REGISTRO DE LECTURA
        test al,100000b     ; REGISTRO DE SALIDA DISPONIBLE
        jz espera
        poke rtd,dato      ; ESCRIBE EL DATO
        endm
       
       
;INICIALIZCIÓN DEL PUERTO A UNA VELODIAD
rs232_ini macro velocidad
        poke lc,80h         ; ACCESO A CONFIGURACIÓN DE VELOCIDAD
        mov bx,velocidad     ;ALAMACENA LA VELOCIDAD
        poke lsb,bl
        poke msb,bh
        poke lc,3           ;CONFIUGURA 8 BITS DE TRANSMISIÓN- 1 BIT DE STOP. SIN PARIDAD
        poke mc,0          
        poke ie,0
        endm

martes, 12 de noviembre de 2013

AMPLIACIÓN DE LA LIBRERÍA IO

   Vamos a ampliar la librería IO de manera que tengamos las funciones PEEK y POKE, que nos permitirán leer y escribir en un puerto del hardware.


    Esto, también, es un paso previo para la próxima entrada en la que  usaremos estas funciones para crear funciones de manejo del 8050, como puerto serie, creando un nivel de enlace mediante dos funciones getcaux, putcaux.

    Con estas últimas crearé un protocolo DH+ Network, para usar de forma sencillas en nuestras aplicaciones de comunicación serie, creando un nivel de transporte con las funciones send_dh y recive_dh.
   
   Estas nuevas funciones nos servirán así mismo, para manejar el puerto CENTRONICS. 
   En posteriores entradas veremos cómo usarlo para manejar hadware acoplado a él.
    Para dar más cache al blog incluiré algo de hardware,  para acoplar al puerto centronics y así poder convertir el ordenador en osciloscopio, analizador, o autómata a través del puerto Centronics.


     Ahora simplemente ampliaremos la cabecera IO.MAC, con estas dos funciones. Incluyo toda la cabecera nueva.
    Estas funciones las añado a IO, por considerar esta cabecera como una de Entrada-Salida no estándar, entendiendo como estándar el teclado  y la pantalla.
    Indico en rojo lo nuevo
IO.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 manejo de unidades
ifndef _unidades
    _unidades equ 1
;unidades
_A equ  0
_B equ 1
_C equ 2
_D equ 3
endif

; constantes para manejo de archivos
ifndef _atributos
   _atributos equ 1
;;atributos de fichero
_O_READ  equ 1
_HIDE    equ 2
_SISTEM  equ 4
_VOL     equ 8
_DIR     equ 16
_ARCHIVO equ 32
_TODOS   equ 00111111B
endif

;posiciones de fseek
_INICIO EQU 0
_FIN    EQU 2
_ULTIMA EQU 3

;; modos de acceso
_R EQU 0
_W EQU 1
_R_W EQU 2

;;Estructuras
_DTA struc
   _RES_DTA DB 21 DUP (?)
   _ATTR    DB ?
   _HORA    DW ?
   _FECHA   DW ?
   _LONG    DD ?
   _NOMBRE  DB 13 DUP (?)
   ENDS

;dispositivos standar
_stdin equ 0
_stdout equ 1
_stderr equ 2
_stdaux equ 3
_stdprn equ 4








;; file direccion cadena ascii fichero
;;handle numero de fichero o codigo de retorno
;;atributo es el tipo de fichero
;;si cf =1 error
;;si cf=0 ax es numero de fichero

newfile macro file,atributo,handle
     mov ah,3ch
     push cx
     push dx
     mov cx,atributo
     lea dx,file
     int 21h
     pop dx
     pop cx
     mov handle,ax
 endm


;abre un fichero. 
; devuelve cf=0 si ok y el handle en la variable handle
;devuelve cf=1 si error y el error en la variable handle
open macro file,atributo,handle

     mov ah,3dh
     mov al,atributo
     push dx
     lea dx,file
     int 21h
     pop  dx
     mov handle,ax
 endm

close macro handle
     mov ah,3eh
     push bx
     mov bx,handle
     int 21h
     pop bx
 endm


;;fichero encontrado esta escrito en la zona DTA
;;      offset descripcion
;;       0      reservado para dos
;;      21      atributo de fichero encontado
;;      22      hora
;;      24      fecha
;;      26      tamaño
;;      30      nombre del fichero y extension
;; devuelve CF=1 si hay error
findfirst macro file,atributo
ifndef _find_first
        extrn _find_first:near
endif
        lea ax,file
        push ax
        mov ax,atributo
        push ax
        call _find_first
  endm


findnext macro
ifndef _find_next
        extrn _find_next:near
endif
        call _find_next
  endm

;; posicion en un fichero el puntero
;; cx marca la parte alta de la direccion
;; para hacerlo mas sencillo nos limitaremos a 65535 bytes por lo que
;; cx=0
;; el metodo es
;;      0    principio fichero
;;      1    desde la posicion actual
;;      2    desde final de fichero
;; devuelve en dx:ax la direccion en que se ha quedado referida al principo del fichero

fseek macro handle,metodo,posicion
ifndef _fseek
        extrn _fseek:near
endif
        mov ax,handle
        push ax        
        mov ax,metodo
        push ax
        mov ax,posicion
        push ax
        call _fseek

 endm

;;obtine direcion de transferencia de disco
;;devuelve en ax un codigo de retorno
;;devuelve en es:bx direccion de DTA
offsetdta macro
      mov ah,2fh
      int 21h
  endm



;READ y WRITE devuelven en ax el número de bytes leidos
;realmente.

read macro handle,n_bytes,buffer
ifndef _read
        extrn _read:near
endif
        mov ax,handle
        push ax
        mov ax,n_bytes
        push AX
        mov ax,offset buffer
        push ax
        call _read

 endm

;lee de un fichero

rseek macro handle,numero,registro

ifndef _rseek
        extrn _rseek:near
endif
        mov ax,handle
        push ax
        mov ax,numero
        push ax
        mov ax,size registro
        push ax
        call _rseek

 endm

; indica el DTA
setdta macro posicion
      mov ah,1ah
      PUSH DX
      lea dx,posicion
      int 21h
      POP DX
  endm

;escribe en un fichero write macro handle,n_bytes,buffer
ifndef _write
        extrn _write:near
endif
        mov ax,handle
        push ax
        mov ax,n_bytes
        push AX
        lea ax,buffer
        push ax
        call _write

 endm







;Toma el path de un camino getpath macro camino,path
ifndef _getpath
      extrn _getpath:near
endif
      lea ax,camino
      push ax
      lea ax,path
      push ax
      call _getpath

endm
 
    ; envía un dato a un puerto IO
poke macro direc,dato
        push dx
        mov dx,direc
        mov al,dato
        out dx,al
        pop dx
        endm



;lee un dato de un puerto IO
peek macro direc
        push dx
        mov dx,direc
        in al,dx
        pop dx
        endm


domingo, 15 de septiembre de 2013

CABECERA ERROR


    Hoy vamos a terminar de completar las funciones básicas para poder crear programas.  Y lo haremos con unas funciones de presentación de errores.
   Como siempre primero las cabeceras.
    A partir de ahora ya tenemos una librería básica bastante potente para poder hacer casi de todo.




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

errext macro
ifndef _print_error
       extrn _print_error:near
endif
       call _print_error
endm

perror macro numero
ifndef _p_error
        extrn _p_error:near
endif
        mov ax,numero
        push ax
        call _p_error
        pop ax
 endm