Vistas de página en total

jueves, 30 de enero de 2014

EMULADOR 8051 (6/12) (LISTADO)


   Como función superior a las anteriores está la que pongo hoy. Esta función generará el listado completo del programa sobre fichero, apoyándose en las anteriores: PRN_INST e INTERPRETE.

    Abrirá un fichero e irá enviando a él todas las líneas de programa desensambladas.



LISTADO.ASM


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

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

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

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

include main.mac
include string.mac
include io.mac

.model compact,pascal

        public listado
.data
extrn prn_ini:word
extrn prn_fin:word
extrn nombrelst:byte
public bufferprn
dato dw 0,0
bufferprn db 50 dup (0)
handle dw 0
nb dw 0
tab1 db " ",0
tab db "       ",0


.code
        
        extrn interpreta:near
        extrn prn_inst:near
        extrn Dma_on:near
        extrn Dma_off:near
listado proc near
        call Dma_on
        creat nombrelst,_Archivo,handle

        mov dx,prn_ini
 otro:
        mov dato,dx
        itoa bufferprn,dato,16
        strlen bufferprn
        mov nb,ax
        cmp ax,3
        jz t3
        strcat bufferprn,bufferprn,tab1
        cmp nb,2
        jz t3
        strcat bufferprn,bufferprn,tab1
t3:
        strcat bufferprn,bufferprn,tab
        call prn_inst
        strlen bufferprn
        mov nb,ax
        write handle,nb,bufferprn
n_prn:
        call interpreta
        mov bx,ax
        mov al,[bx]
        cmp al,0
        jz contado
        inc dx
        cmp al,2
        jz acuenta
        cmp al,4
        jz acuenta
        cmp al,5
        jz acuenta
        cmp al,8
        jnz contado
acuenta:
        inc dx
contado:
        cmp dx,prn_fin
        jae fin
        jmp otro
fin:
        close handle
        call Dma_off
        ret

listado endp

end listado



martes, 28 de enero de 2014

EMULADOR 8051 (5/12) (DESENSAMBLADOR SOBRE BUFFER)

    Como deseamos tener una copia del programa en papel para analizarlo con tranquilidad, debemos tener la posibilidad de imprimir el programa desensamblado, o almacenarlo en un fichero.

    Esta es, pues, la versión de listado de programa sobre buffer. Básicamente es la misma que la de impresión de pantalla, con la salvedad de que aquí no se limitará a un número concreto de instrucciones, sino que realizará el programa completo. Pero ese control lo llevará el programa padre. Este versión de la instrucción se limita a cambiar la salida de impresión de la pantalla a un buffer de impresión llamado bufferprn, sobre el que se generará el listado y que posteriormente será lanzado sobre la impresora o a un fichero.

PRN_INST.ASM


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

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

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

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



include main.mac
include stdio.mac
include io.mac
include string.mac

.model compact,pascal

             public prn_inst
.data
extrn bufferprn:byte
dato dw 0,0
registro db "P0.",5 DUP (0)
         db "TCON.",3 DUP (0)
         db "P1.",5 DUP (0)
         db "SCON.",3 DUP (0)
         db "P2.",5 DUP (0)
         db "IE.",5 DUP (0)
         db "P3.",5 DUP (0)
         db "IP.",5 DUP (0)
         db "PSW.",4 DUP (0)
         db "ACC.",4 DUP (0)
         db "B.",6 DUP (0)
hprn dw 0
numero db 10 dup (0)
nlinea db 13,10,0
mas db "+",0
menos db  "-",0

code
        
       
        extrn interpreta:near
        extrn lee:near
prn_inst proc near  uses dx cx bx
        
        call interpreta
        mov bx,ax
        mov al,[bx]
        cmp al,0                        ;solo codigo instrucc. de 1 byte
        jnz decod1
        strcat bufferprn,bufferprn,[bx+3]
        jmp linea
decod1:
        cmp al,1                 ;1 codigo inst , 1 byte de dato
        jnz decod2
        strcat bufferprn,bufferprn,[bx+3]
        call lee
        inc dx
        mov cl,al
        mov ch,0
        mov dato,cx
        itoa numero,dato,@h
        strcat bufferprn,bufferprn,numero
        jmp linea
decod2:
        cmp al,2                ;1codico + 2 byte
        jnz decod3
        strcat bufferprn,bufferprn,[bx+3]
        call lee
        inc dx
        mov ch,al
        call lee
        inc dx
        mov cl,al
        mov dato,cx
        itoa numero,dato,@h
        strcat bufferprn,bufferprn,numero
        jmp linea

decod3:
        cmp al,3                ;1 codigo + 1 byte + codigo
        jnz decod4
        strcat bufferprn,bufferprn,[bx+3]
        call lee
        inc dx
        mov cl,al
        mov ch,0
        mov dato,cx
        itoa numero,dato,@h
        strcat bufferprn,bufferprn,numero
        inc bx
        inc bx
busca1:
        inc bx
        cmp byte ptr [bx],0
        jnz busca1
        strcat bufferprn,bufferprn,[bx+1]
        jmp linea

decod4:                         ;1 codigo + 2 byte + codigo
        cmp al,4
        jnz decod5
        strcat bufferprn,bufferprn,[bx+3]
        call lee
        inc dx
        mov cl,al
        call lee
        inc dx
        mov ch,al
        mov dato,cx
        itoa numero,dato,@h
        strcat bufferprn,bufferprn,numero
        inc bx
        inc bx
busca2:
        inc bx
        cmp byte ptr [bx],0
        jnz busca2
        strcat bufferprn,bufferprn,[bx+1]
        jmp linea
decod5:
        cmp al,5                ;1 codigo + 1 byte relativo + codigo + byte
        jz escod5
        jmp DECOD6
escod5:
        strcat bufferprn,bufferprn,[bx+3]
        call lee
        inc dx
        mov cl,al
        mov ch,0
        cmp cl,0
        jz busc3
        test cx,80h
        jz positivo1
        strcat bufferprn,bufferprn,menos
        not cl
        inc cx
        jmp short negativo1
positivo1:
        strcat bufferprn,bufferprn,mas
negativo1:
        mov dato,cx
        itoa numero,dato,@h
        strcat bufferprn,bufferprn,numero
busc3:
        inc bx
        inc bx
busca3:
        inc bx
        cmp byte ptr [bx],0
        jnz busca3
        strcat bufferprn,bufferprn,[bx+1]
        call lee
        inc dx
        mov cl,al
        mov ch,0
        mov dato,cx
        itoa numero,dato,@h
        strcat bufferprn,bufferprn,numero
        jmp linea

decod6:
        cmp al,6                        ;SALTO RELATIVO
        jnz decod7
        strcat bufferprn,bufferprn,[bx+3]
        call lee
        inc dx
        cbw
        add ax,dx
        mov cx,ax
        mov dato,cx
        itoa numero,dato,@h
        strcat bufferprn,bufferprn,numero
        jmp linea

decod7:
        cmp al,7                ;1 codigo + 1 byte relativo + codigo
        jz ss1
        jmp caso8
ss1:
        strcat bufferprn,bufferprn,[bx+3]
        call lee
        inc dx
        mov cl,al
        mov ch,0
        cmp cl,0
        jz busc7
        test cx,80h
        jz positivo
        strcat bufferprn,bufferprn,menos
        not cl
        inc cx
        jmp short negativo
positivo:
        strcat bufferprn,bufferprn,mas
negativo:
        mov dato,cx
        itoa numero,dato,@h
        strcat bufferprn,bufferprn,numero
busc7:
        inc bx
        inc bx
busca7:
        inc bx
        cmp byte ptr [bx],0
        jnz busca7
        strcat bufferprn,bufferprn,[bx+1]
        jmp linea

caso8:
        cmp al,8
        jz ss2
        jmp caso9
ss2:
        strcat bufferprn,bufferprn,[bx+3]
        call lee
        inc dx
        mov cl,al
        mov ch,0
        mov dato,cx
        itoa numero,dato,@h
        strcat bufferprn,bufferprn,numero
        inc bx
        inc bx
busca8:
        inc bx
        cmp byte ptr [bx],0
        jnz busca8
        strcat bufferprn,bufferprn,[bx+1]
        call lee
        inc dx
        mov cl,al
        mov ch,0
        mov dato,cx
        itoa numero,dato,@h
        strcat bufferprn,bufferprn,numero
        jmp linea
caso9:
        cmp al,9                ;texto + direc 8 bits + texto + dato 8 bits rel
        jnz alcaso9
        jmp caso10
alcaso9:
        strcat bufferprn,bufferprn,[bx+3]
        call lee
        inc dx
        mov cl,al
        mov ch,0
        mov dato,cx
        itoa numero,dato,@h
        strcat bufferprn,bufferprn,numero
        inc bx
        inc bx
busca9:
        inc bx
        cmp byte ptr [bx],0
        jnz busca9
        strcat bufferprn,bufferprn,[bx+1]
        call lee
        inc dx
        cbw
        add ax,dx
        mov dato,AX
        itoa numero,dato,@h
        strcat bufferprn,bufferprn,numero
        jmp linea

caso10:
        cmp al,10                ;texto + direcc 11 bits
        jnz alcaso10
        jmp caso11
alcaso10:
        strcat bufferprn,bufferprn,[bx+3]
        dec dx      ;releeo el codigo para obtener la parte alta de la direccion
        call lee
        inc dx
        mov cl,5
        shr al,cl
        mov ch,al
        call lee
        inc dx
        mov cl,al
        mov  dato,cx
        itoa numero,dato,@h
        strcat bufferprn,bufferprn,numero
        jmp linea
caso11:
        cmp al,11                ;texto + bit
        jnz alcaso11
        jmp caso12
alcaso11:
        strcat bufferprn,bufferprn,[bx+3]
        call lee
        inc dx
        cmp al,7fh
        jbe directo
        push bx
        sub al,80h
        mov ah,al
        and al,07h
        push ax
        and ah,0f8h
        mov bl,ah
        xor bh,bh
        mov si,offset registro
        strcat bufferprn,bufferprn,[bx+3]     ;envia nombre del registro
        pop ax
        pop bx
directo:
        mov cl,al
        mov  dato,cx
        itoa numero,dato,@h
        strcat bufferprn,bufferprn,numero
        jmp linea
caso12:
        cmp al,12                ;texto + bit + texto
        jnz alcaso12
        jmp caso13
alcaso12:
        strcat bufferprn,bufferprn,[bx+3]
        call lee
        inc dx
        cmp al,7fh
        jbe directo12
        push bx
        sub al,80h
        mov ah,al
        and al,07h
        push ax
        and ah,0f8h
        mov bl,ah
        xor bh,bh
        mov si,offset registro
        strcat bufferprn,bufferprn,[bx+si]   ;envia nombre del registro
        pop ax
        pop bx
directo12:
        mov cl,al
        mov  dato,cx
        itoa numero,dato,@h
        strcat bufferprn,bufferprn,numero
        inc bx
        inc bx
busca12:
        inc bx
        cmp byte ptr [bx],0
        jnz busca12
        strcat bufferprn,bufferprn,[bx+1]
        jmp linea
caso13:
        cmp al,13                ;texto + bit + texto
        jnz alcaso13
        jmp linea
alcaso13:
        strcat bufferprn,bufferprn,[bx+3]
        call lee
        inc dx
        cmp al,7fh
        jbe directo13
        push bx
        sub al,80h
        mov ah,al
        and al,07h
        push ax
        and ah,0f8h
        mov bl,ah
        xor bh,bh
        mov si,offset registro
        strcat bufferprn,bufferprn,[bx+si]   ;envia nombre del registro
        pop ax
        pop bx
directo13:
        mov cl,al
        mov  dato,cx
        itoa numero,dato,@h
        strcat bufferprn,bufferprn,numero

        inc bx
        inc bx
busca13:
        inc bx
        cmp byte ptr [bx],0
        jnz busca13
        strcat bufferprn,bufferprn,[bx+1]
        call lee
        inc dx
        cbw
        add ax,dx
        mov dato,AX
        itoa numero,dato,@h
        strcat bufferprn,bufferprn,numero
        jmp linea

linea:
        strcat bufferprn,bufferprn,nlinea

        ret
prn_inst endp

end prn_inst

sábado, 25 de enero de 2014

EMULADOR 8051 (3B/12) (RUTINA INSERTADA POR "REGISTROS")

   En la entrada de la rutina que recogía e imprimía en pantalla el valor de los registros, aparecía en código máquina del 8051, en la data, la rutina que debería copiarlos a memoria para que el proceso pudiera pasarlo al pc.
   Dado que el código máquina no es muy claro, pongo hoy la rutina escrita en ensamblador 8051. Esta rutina saca el valor de los registros a la memoria, de donde los recoge el programa.

   Por supuesto, esta rutina debe de ser compilada con un compilador de ensamblador para el 8051.


EXTRACCIÓN DE REGISTRO


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

     ;RUTINA DE EXTRACCIÓN DE REGISTROS
       ; MICROPROCESADOR 8051
       
       DEFSEG CERO,START=0

       SEG CERO

        MOV DPTR,#70H   ;P0
        MOV A,80H
        MOVX @DPTR,A
        INC DPTR
        MOV A,81H
        MOVX @DPTR,A   ;SP
        INC DPTR
        MOV A,88H      ;TCON
        MOVX @DPTR,A
        INC DPTR
        MOV A,89H      ;TMOD
        MOVX @DPTR,A
        INC DPTR
        MOV A,8AH      ;TL0
        MOVX @DPTR,A
        INC DPTR
        MOV A,8BH      ;TL1
        MOVX @DPTR,A
        INC DPTR
        MOV A,8CH      ;TH0
        MOVX @DPTR,A
        INC DPTR
        MOV A,8DH      ;TH1
        MOVX @DPTR,A
        INC DPTR
        MOV A,90H      ;P1
        MOVX @DPTR,A
        INC DPTR
        MOV A,98H      ;SCON
        MOVX @DPTR,A
        INC DPTR
        MOV A,89H      ;SBUF
        MOVX @DPTR,A
        INC DPTR
        MOV A,0A0H      ;P2
        MOVX @DPTR,A
        INC DPTR
        MOV A,0A8H      ;IE
        MOVX @DPTR,A
        INC DPTR
        MOV A,0B0H      ;P3
        MOVX @DPTR,A
        INC DPTR
        MOV A,0B8H      ;IP
        MOVX @DPTR,A
        INC DPTR
        MOV A,0D0H      ;PSW
        MOVX @DPTR,A
        INC DPTR
        MOV A,0E0H      ;ACC
        MOVX @DPTR,A
        INC DPTR
        MOV A,0F0H      ;B
        MOVX @DPTR,A
        INC DPTR
        MOV A,R0      ;R0
        MOVX @DPTR,A
        INC DPTR
        MOV A,R1      ;R1
        MOVX @DPTR,A
        INC DPTR
        MOV A,R2      ;R2
        MOVX @DPTR,A
        INC DPTR
        MOV A,R3      ;R3
        MOVX @DPTR,A
        INC DPTR
        MOV A,R4      ;R4
        MOVX @DPTR,A
        INC DPTR
        MOV A,R5      ;R5
        MOVX @DPTR,A
        INC DPTR
        MOV A,R6      ;R6
        MOVX @DPTR,A
        INC DPTR
        MOV A,R7      ;R7
        MOVX @DPTR,A


        END

viernes, 24 de enero de 2014

EMULADOR 8051 (4/12) (DESENSAMBLADOR)

   Esta rutina será el nivel superior al interprete colocado dos entradas atrás. Apoyándose en el intérprete, esta función compondrá el texto completo de la instrucción en ensamblador, con los datos correspondiente de la instrucción.
  Para conseguirlo llamará con el código máquina de la instrucción al Intérprete, el cual le devolverá un puntero a la estructura de la instrucción. Según esta estructura, el desensamblador irá imprimiendo los textos que representan el código de instrucción e irá leyendo el resto de los datos para presentarlos posteriormente.


   Por todo esto la instrucción la llamé "presenta instrucción", dado que la hice de forma que directamente presentaba en pantalla la instrucción. Para usarla, simplemente, el programa que genera el listado de instrucciones irá situando en pantalla el puntero e irá llamando a esta función pasando en dx el offset de la instrucción en código máquina correspondiente.

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

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

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

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

include main.mac
include stdio.mac
.model compact,pascal
         public pres_inst
         
.data
dato dw 0,0
;lista de registros para colocar en su lugar durante la interpretación de la instrucción
registro db "P0.",5 DUP (0)
         db "TCON.",3 DUP (0)
         db "P1.",5 DUP (0)
         db "SCON.",3 DUP (0)
         db "P2.",5 DUP (0)
         db "IE.",5 DUP (0)
         db "P3.",5 DUP (0)
         db "IP.",5 DUP (0)
         db "PSW.",4 DUP (0)
         db "ACC.",4 DUP (0)
         db "B.",6 DUP (0)


.code
       
        extrn interpreta:near
        extrn lee:near
pres_inst proc uses cx bx
      ;en dx se le psasrá la direccción del código a interpretar
        call interpreta     ;llama a la interpretación indicando la dirección en dx
        mov bx,ax
        mov al,[bx]
        cmp al,0                        ;solo codigo instrucc. de 1 byte
        jnz decod1
        printf byte ptr [bx+3]
        jmp linea
decod1:
        cmp al,1                 ;1 codigo inst , 1 byte de dato
        jnz decod2
        printf byte ptr [bx+3]
        call lee
        inc dx
        mov cl,al
        mov ch,0
        mov dato,cx
        printf dato,@h
        jmp linea
decod2:
        cmp al,2                ;1codico + 2 byte
        jnz decod3
        printf byte ptr [bx+3]
        call lee
        inc dx
        mov ch,al
        call lee
        inc dx
        mov cl,al
        mov  dato,cx
        printf dato,@h
        jmp linea

decod3:
        cmp al,3                ;1 codigo + 1 byte + codigo
        jnz decod4
        printf byte ptr [bx+3]
        call lee
        inc dx
        mov cl,al
        mov ch,0
        mov dato,cx
        printf dato,@h
        inc bx
        inc bx
busca1:
        inc bx
        cmp byte ptr [bx],0
        jnz busca1
        printf byte ptr [bx+1]
        jmp linea

decod4:                         ;1 codigo + 2 byte + codigo
        cmp al,4
        jnz decod5
        printf byte ptr [bx+3]
        call lee
        inc dx
        mov cl,al
        call lee
        inc dx
        mov ch,al
        mov dato,cx
        printf dato,@h
        inc bx
        inc bx
busca2:
        inc bx
        cmp byte ptr [bx],0
        jnz busca2
        printf byte ptr [bx+1]
        jmp linea
decod5:
        cmp al,5                ;1 codigo + 1 byte relativo + codigo + byte
        jz escod5
        jmp DECOD6
escod5:
        printf byte ptr [bx+3]
        call lee
        inc dx
        mov cl,al
        mov ch,0
        cmp cl,0
        jz busc3
        test cx,80h
        jz positivo1
        putchar '-'
        not cl
        inc cx
        jmp short negativo1
positivo1:
        putchar '+'
negativo1:
        mov dato,cx
        printf dato,@h
busc3:
        inc bx
        inc bx
busca3:
        inc bx
        cmp byte ptr [bx],0
        jnz busca3
        printf byte ptr [bx+1]
        call lee
        inc dx
        mov cl,al
        mov ch,0
        mov dato,cx
        printf dato,@h
        jmp linea

decod6:
        cmp al,6                        ;SALTO RELATIVO
        jnz decod7
        printf byte ptr [bx+3]
        call lee
        inc dx
        cbw
        add ax,dx
        mov dato,AX
        printf dato,@h
        jmp linea

decod7:
        cmp al,7                ;1 codigo + 1 byte relativo + codigo
        jnz caso8
        printf byte ptr [bx+3]
        call lee
        inc dx
        mov cl,al
        mov ch,0
        cmp cl,0
        jz busc7
        test cx,80h
        jz positivo
        putchar '-'
        not cl
        inc cx
        jmp short negativo
positivo:
        putchar '+'
negativo:
        mov dato,cx
        printf dato,@h
busc7:
        inc bx
        inc bx
busca7:
        inc bx
        cmp byte ptr [bx],0
        jnz busca7
        printf byte ptr [bx+1]
        jmp linea

caso8:
        cmp al,8                ;texto + direc 8 bits + texto + dato 8 bits
        jnz caso9
        printf byte ptr [bx+3]
        call lee
        inc dx
        mov cl,al
        mov ch,0
        mov dato,cx
        printf dato,@h
        inc bx
        inc bx
busca8:
        inc bx
        cmp byte ptr [bx],0
        jnz busca8
        printf byte ptr [bx+1]
        call lee
        inc dx
        mov cl,al
        mov ch,0
        mov dato,cx
        printf dato,@h
        jmp linea

caso9:
        cmp al,9                ;texto + direc 8 bits + texto + dato 8 bits rel
        jnz caso10
        printf byte ptr [bx+3]
        call lee
        inc dx
        mov cl,al
        mov ch,0
        mov dato,cx
        printf dato,@h
        inc bx
        inc bx
busca9:
        inc bx
        cmp byte ptr [bx],0
        jnz busca9
        printf byte ptr [bx+1]
        call lee
        inc dx
        cbw
        add ax,dx
        mov dato,AX
        printf dato,@h
        jmp linea

caso10:
        cmp al,10                ;texto + direcc 11 bits
        jnz caso11
        printf byte ptr [bx+3]
        dec dx      ;releeo el codigo para obtener la parte alta de la direccion
        call lee
        inc dx
        mov cl,5
        shr al,cl
        mov ch,al
        call lee
        inc dx
        mov cl,al
        mov  dato,cx
        printf dato,@h
        jmp linea
caso11:
        cmp al,11                ;texto + bit
        jnz caso12
        printf byte ptr [bx+3]
        call lee
        inc dx
        cmp al,7fh
        jbe directo
        push bx
        sub al,80h
        mov ah,al
        and al,07h
        push ax
        and ah,0f8h
        mov bl,ah
        xor bh,bh
        mov si,offset registro
        printf byte ptr [bx+si]   ;envia nombre del registro
        pop ax
        pop bx
directo:
        mov cl,al
        mov  dato,cx
        printf dato,@h
        jmp linea
caso12:
        cmp al,12                ;texto + bit + texto
        jnz caso13
        printf byte ptr [bx+3]
        call lee
        inc dx
        cmp al,7fh
        jbe directo12
        push bx
        sub al,80h
        mov ah,al
        and al,07h
        push ax
        and ah,0f8h
        mov bl,ah
        xor bh,bh
        mov si,offset registro
        printf byte ptr [bx+si]   ;envia nombre del registro
        pop ax
        pop bx
directo12:
        mov cl,al
        mov  dato,cx
        printf dato,@h
        inc bx
        inc bx
busca12:
        inc bx
        cmp byte ptr [bx],0
        jnz busca12
        printf byte ptr [bx+1]
        jmp linea
caso13:
        cmp al,13                ;texto + bit + texto + dato 8bits
        jz acaso13
        jmp linea
acaso13:
        printf byte ptr [bx+3]
        call lee
        inc dx
        cmp al,7fh
        jbe directo13
        push bx
        sub al,80h
        mov ah,al
        and al,07h
        push ax
        and ah,0f8h
        mov bl,ah
        xor bh,bh
        mov si,offset registro
        printf byte ptr [bx+si]   ;envia nombre del registro
        pop ax
        pop bx
directo13:
        mov cl,al
        mov  dato,cx
        printf dato,@h

        inc bx
        inc bx
busca13:
        inc bx
        cmp byte ptr [bx],0
        jnz busca13
        printf byte ptr [bx+1]
        call lee
        inc dx
        cbw
        add ax,dx
        mov dato,AX
        printf dato,@h
        jmp linea

linea:
        ret
pres_inst endp

end pres_inst

martes, 14 de enero de 2014

EMULADOR 8051 (3/12) (REGISTROS)

    Ya podemos, decodificar el programa a ensamblador, y podemos ver el contenido de la memoria en formato de datos. ¿Pero que pasa con los registros de microcontrolador?
    Eso no es accesible a través del bus, ya que no está dentro de la memoria. Por lo tanto parece imposible que podamos mostrarlo en la pantalla, sin que exista un programa uploader dentro del programa de microporcesador o de la tarjeta prototipo. Pero eso no es verdad.
    Dado que tengo todo el control sobre la ejecución del microcontrolador, puedo parlo cuando quiera, accedera a la memoria y cambiarla cuando desee, e incluso ejecutar una instrucción en micropasos. Por ello, ¿porqué no puedo intervenir en la ejecuión de un programa de forma intempestiva? Pues eso... si puedo.

     Por esto, si soy capaz de leer los registros, sin haber incorporado ninguna rutina previa en el prototipo. Me basta conque la memoria de programa sea ram, para que pueda modificarla en todo momento.
      Si la memoria es ram, puedo volcar el programa y luego ejecutarle. Pero como los pulsos de reloj los controlo uno a uno desde el PC, puedo parar el programa en cualquier instrución, y claro puedo entretenermo lo que desee en ese punto.... Hasta puedo escribir y lleer en la memoria mientras tengo el procesador parado.... entonces, porque no substituir el programa.
    Pues eso vamos a hacer. Para poder ver los registros, vamos a parar el programa en un punto de ruptura, y en ese punto que se pare querremos ver los registros. Pues entonces, vamos a escribir un pequeño programa dentro de la memoria, que nos guarde los valores de los registros en una zona de memoria. 
    Una vez copiado este programa lo vamos a ejecutar, y luego tomaremos los valores que nos haya copiado.
      Para que sea transparente, este programa lo almacenaremos en la dirección 0 si nos encontramos ejecutando por encima de 255, y en 100h si estamos ejecutando por debajo.
         El proceso sera básicamente este:
           1  Elegimos el area de volcado de la rutina.
           2  Toma la dirección de este area de memoria y se acopla a la instrucción de salto     
           3  Salvaguarda en el pc el area de memoria 8051 que será ocupada por la rutina_reg,y el valor de los gegistros 90h bytes
           4  Guarda  la direccion actual de ejecución (IP) en dir_ini   
           5  Salvaguarda en PC el contenido de memoria donde irá la instrucción de salto (3 bytes)
           6  Se coloca la instruccion de salto  nueva en la actual dirección del IP dentro del 8051
           7  Ejecutamos este salto
           8  Se restaura la instrución original almacenada en el pc en el paso 5
           9  Se coloca la rutina de volcado en la memoria del 8051
           10  Ejecutaremos la rutina.
           11 Recogeremos el valor de los registros. Los últimos 32 bytes de la memoria, del área temporal
           12  Restauraremos las areas de memoria de instrucción y de datos usadas en el 8051.
             
       Como la rutina no la vamos a colocar en el punto de ejecución en que esté en este momento el programa, deberemos hacer algo para que se enlacen. Para esto,  usaremos una pequeña instrucción de salto asignada a la dirección de volcado de la rutina. Así antes de ejecutar la rutina copiaremos el valor que tiene  la memoria de la dirección IP actual indicada en DIR_cur,copiaremos la instrucción de salto a la nueva rutina, la ejecutaremos y restauraremos posteriormente los tres byte originales en la dirección del IP (Instruction pointer) a su valor original.
           Con todo esto logramos ejecutar un programa sin haber gastado un solo byte para este drive. Es un dirve de quita y pon y por lo tanto transparente.

        Aquí queda la rutina.


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

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

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

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

include main.mac
include stdio.mac
include 48iocent.mac
include window.mac

               public prn_reg
.model compact,pascal


.data
extrn vez_reg:byte        ;variables globales del emulador
extrn Dir_cur:word        ;dirección actual del ip. Dirección de ejecución actual

;esta es la secuencia de código máquina del 8051 de la rutina de extracción

Rutina_reg db 90H,00H,70H,0E5H,80H,0F0H,0A3H,0E5H,81H,0F0H,0A3H,0E5H,88H,0F0H,0A3H,0E5H,89H,0F0H,0A3H
           DB 0E5H,8AH,0F0H,0A3H,0E5H,8BH,0F0H,0A3H,0E5H,8CH,0F0H,0A3H,0E5H,8DH,0F0H,0A3H
           DB 0E5H,90H,0F0H,0A3H,0E5H,98H,0F0H,0A3H,0E5H,99H,0F0H,0A3H,0E5H,0A0H,0F0H,0A3H
           DB 0E5H,0A8H,0F0H,0A3H,0E5H,0B0H,0F0H,0A3H,0E5H,0B8H,0F0H,0A3H,0E5H,0D0H,0F0H,0A3H
           DB 0E5H,0E0H,0F0H,0A3H,0E5H,0F0H,0F0H,0A3H,0E8H,0F0H,0A3H,0E9H,0F0H,0A3H,0EAH,0F0H
           DB 0A3H,0EBH,0F0H,0A3H,0ECH,0F0H,0A3H,0EDH,0F0H,0A3H,0EEH,0F0H,0A3H,0EFH,0F0H
 db 2
Dir_ini db 0,0    ;dirección inicial donde comienza el proceso. Usada para restaurar.
Salto db 2,0,0    ; insgtrucción de salto para pasar a la rutina

dir_salto dw 0
dato dw 0,0
Memo_ini db 90H dup (0)    ;memoria inicial
Inst_ini db 5 dup (0)     ;instrucción inicial
registros db 40 dup (0)  ;buffer para los registros
;mensajes para pantalla
Mreg db "Registros",0
MR0 DB "R0=",0
MR1 DB "R1=",0
MR2 DB "R2=",0
MR3 DB "R3=",0
MR4 DB "R4=",0
MR5 DB "R5=",0
MR6 DB "R6=",0
MR7 DB "R7=",0



.code
        extrn _trace:near
        extrn Guarda:near
        extrn Toma:near
prn_reg proc uses bx dx cx si

        mov ax,Dir_cur     ;valor de IP actual
        cmp ax,255        ;Si se está ejecutando por encima del byte 255, se grabará la rutina  temporal en byte 0
        ja abajo
        mov dir_salto,100h   ;Si estamos por debajo de 255, lo haremos en la dirección 100h
        jmp short tomar
abajo:
        mov dir_salto,0
tomar:
        mov dx,dir_salto     ;tomamos la dirección deseada del salto y se acopla a la instrucción de salto
        mov salto+1,dh
        mov salto+2,dl

        ;se salvaguarda el area que será substituida por la rutina_reg
        mov bx,offset Memo_ini   ;almacena en pc la memoria del sistema
        mov cx,90h        ;longitud de la rutina_reg
        call Toma               ;toma la zona de la instruccion de salto
        
        mov dx,Dir_cur      ;Se guarda  la direccion actual de ejecución en dir_ini 
        mov Dir_ini,dh       ;para regresar a ella posteriormente
        mov dir_ini+1,dl
         
        mov bx,offset Inst_ini    ;almacenamos el contenido de memoria donde irá la instrucción de salto
        mov cx,3
        call Toma
        
        
        mov dx,Dir_cur          ;coloca la instruccion de salto  nueva en la actual dirección del IP
        mov cx,3
        mov bx,offset Salto
        call Guarda
        
        mov cx,24               ;ejecuta el salto (24 ticks)
        call _trace
        
        mov dx,Dir_ini          ;recupera la instruccion original en la memoria del 8051
        mov bx,offset Inst_ini
        mov cx,3H
        call Guarda
        
        mov dx,dir_salto        ;almacena la rutina de extracción de registros en la posición deseada
        add dx,70h
        mov dh,rutina_reg+1
        mov dl,rutina_reg+2
        mov dx,dir_salto        ;almacena la rutina de registros
        mov bx,offset Rutina_reg
        mov cx,70h
        call Guarda
        
        
        mov cx,1480             ;ejecuta la rutina completa regresando automáticamente (1480 ticks)
        call _trace
        
        mov dx,dir_salto        ;lee el valor de los registros copiados en memoria del 8051
        add dx,70h
        mov bx,offset registros  ;al bufer del ordenador
        mov cx,32
        call Toma
        
        mov dx,dir_salto       ;restaura la memoria inical del sistema 8051
        mov cx,90h
        mov bx,offset Memo_ini
        call Guarda
        
        ;refresca la ventana en pantalla con los valores leidos
        cmp vez_reg,1
        jz nvent
        window 2,60,10,75,Mreg
nvent:
        mov bx,offset registros + 18
        gotoxy 61,3
        printf MR0
        printf word ptr [bx],@H
        gotoxy 61,4
        printf MR1
        printf word ptr [bx+1],@H
        gotoxy 61,5
        printf MR2
        printf word ptr [bx+2],@h
        gotoxy 61,6
        printf MR3
        printf word ptr [bx+3],@h
        gotoxy 61,7
        printf MR4
        printf word ptr [bx+4],@h
        gotoxy 61,8
        printf MR5
        printf word ptr [bx+5],@h
        gotoxy 61,9
        printf MR6
        printf word ptr [bx+6],@h
        gotoxy 61,10
        printf MR7
        printf word ptr [bx+7],@h
        ret
prn_reg endp

end prn_reg

jueves, 9 de enero de 2014

EMULADOR 8051 (2/12) (DUMP )

   Después de las Vacacionesde navidad voy a seguir con el programa de emulación del 8051, sobre la tarjeta puesta en entradas anteriores.
   
  Ya he puesto el código de desensamblado. Es decir el código de la rutina que será capaz de interpretar el programa en código máquina para presentarlo en pantalla.
   El emulador tambén tendrá que ser capaz de presentar en pantalla  los datos de la memoria y modificarlos si es preciso. Para ello deberemos de crar una ventana de "DUMP".
   Por ello voy a exponer en esta entrada del blog la rutina que será capaz de realizar este proceso.
 Como vereis está soportada sobre todas las rutinas que he ido colocando en el blog, las cuales me permiten crear un entrono de ventanas sobre MS-DOS.
   Como el programa ya está analizado y se donde quiero llegar, en el blog como veis no empiezo de arriba hacia abajo. De una análisis del proceso hacia una descomposición. Lo voy haciendo al revés. Voy colocando los procesos ya descompuestos, de abajo a arriba hasta que lleguemos al proceso final.
   Esto lo hago por falta de tiempo. El programa ya está hecho, y su análisis se hizo en su día. Por ello me resulta más cómodo ir colocando las rutinas que hacen cada parte, de forma que puedan servir como ejemplo de uso de algunas funciones, e ir subiendo el proceso apoyandome en lo que ya he expuesto.

    Así también creo un poco de expectativa de lo que seré capaz de hacer....creo.

    Por ello, voy a ir resolviendo las partes fundamentales que hará falta usar desde el hard, que ya ha sido expuesto, pasando por las librerías de control, que ya han sido colocadas, las funciones básicas, que estoy poniendo; para terminar con el entorno de menús y control de ventanas.

     Dado que no he comenzado con el análisis previo de la aplicación que estoy montando en el blog, pero si supongo que puede interesar saber que es todo esto. Voy a incluir el manual de uso. Con él queda claro lo que se podrá hacer, como funcionará y como será el programa final.

MANUAL EMULADOR 8051

   

   En este caso definiremos dos funciones: DUMP y MOD_DATO.
         Dump - Esta subrrutina realiza la presentación en ventana de un area de la memoria del sistema. El area mostrada estádefinida por el tamaño de la ventana. Los datos se mostrarán en 10  filas de 16 datos en hexadecimal. la posición de esta ventana, es fija y está definida en este programa, pues cuando se analizo el interface ya se asignó una zona para cada area.
         MOD_DATO - Esta subrutina permitirá modificar un dato de la memoria del sistema. Será llamada por el entrorno principal cuando se pulse el ratón. En el momento que se haga una pusación del ratón en el programa principal se llamará a todos las rutinas auxiliares de las ventanas de foma consecutiva. Si una asiste a la solicitud es que el ratón estaba dentro de su área. Es por esa razón por la que el programa primero analiza la posición del ratón, si no está en su area sale, permitiendo el análisis al siguiente módulo.
        Esto se hizo para tener los módulos independientes, de forma que el area de asignación del ratón estuviera en el mismo módulo que el area de asignacion de ventanas. Podría haberse hecho mediante constantes, o variables, pero debido a que no necesitaba mover las ventanas de sitio, y a que las constantes me obligaría a recompilar todo cada vez que modificase algo, decidí hacerlo de esta forma.
        No es la más elegante para reubicar, pero es la más simple para independizar. Una vez realizada una rutina, esta no será influida por errores de compilación o de variables durante el desarrollo del resto.

        Si alguien quiere realizar variables, para reubicar las ventanas..... ahí tiene el código.


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

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

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

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/
include main.mac
include stdio.mac
include 48iocent.mac
include mouse.mac
include window.mac
INCLUDE 8051.MAC
        public DUMP
        public mod_dato
       
.model compact,pascal


.data
     ; datos externos definidos como variables globales en el módulo principal
        extrn dir_base:word         ;dirección de memoria incial mostrada en ventana
        extrn vez:byte
        extrn vrfs:byte
        extrn m_ventana:byte
        extrn CONTROL:BYTE

nada db 0
dato dw 0,0
dire dw 0,0
x db 0
y db 0
borra_dir db "    ",0
borra_dat db "  ",0
mdato db "Valor",0
dir_mod dw 0
buffer db 10*16 dup (0)

    
.code
       ; funciones externas

DUMP proc near
        cmp vez,1
        je noventana
        draw_win 12,25,22,78,nada
        gotoxy 78,12
        putchar ' '
        gotoxy 78,22
        putchar ' '
        gotoxy 78,13
        putchar ' '
        gotoxy 78,21
        putchar ' '
        mov cl,14
 barra:
        gotoxy 78,cl
        putchar '¦'
        inc cl
        cmp cl,21
        jnz barra
noventana:
        mov x,31
        mov y,13
        mov bx,dir_base
        cmp vrfs,1
        jz ya_prn
        gotoxy 26,13
        puts borra_dir
        gotoxy 26,13
        printf dir_base,@h
ya_prn:
        mov si,offset buffer
 otro:
        mov dx,bx
        lee
        mov dl,al
        cmp vrfs,0
        jz prn_todo
        cmp [si],dl
        jz no_prn_dato
prn_todo:
        mov byte ptr dato,dl
        gotoxy x,y
        puts borra_dat
        gotoxy x,y
        printf dato,@h
no_prn_dato:
        mov [si],dl
        inc si
        add x,3
        inc bx
        mov ax,bx
        sub ax,dir_base
        mov dx,ax
        and dx,0fh
        mov cl,4
        shr ax,cl
        cmp ax,9                        ;numero de lineas
        jz fin
        cmp dx,0                        ;linea completada
        jnz linea
        inc y
        mov x,31
        cmp vrfs,1
        jz linea
        gotoxy 26,y
        puts borra_dir
        gotoxy 26,y
        mov dire,bx
        printf dire,@h

linea:
        jmp otro
fin:
        mov vrfs,1
        mouse on
        ret

DUMP endp

mod_dato proc near
        mov dato,0
        getmousexy 13,9,31,47              ;verifica si el ratón está dentro de la ventana de datos
        cmp al,0ffh
        jne nwnumero
no_modi:
        mov dato,0
        ret
nwnumero:
        push ax          ;almaceno provisionalmente la posición del ratón
        ;abre una ventana popup para pedir el dato
        getwindow  10,35,12,45,m_ventana,
        draw_win 10,35,12,45,mdato
        gotoxy 36,11
        scanf dato,@h                   ; pide el dato
        putwindow 10,35,12,45,m_ventana
        cmp dato,0ffh
        ja nwnumero       ; si dato no es correcto repite la pregunta
       
        pop ax
        mov dx,ax    ;guardo la posición en dx
        mov ah,0     ;os quedmaos con la y que está en al
        mov bl,16     ;16 datos por fila
        mul bl          ;byte de desplazamineto inicial de la fila
        add ax,dir_base  ;dirección del primer dato mostrado en ventana
        push ax         ;guardo la dirección inicial de la fila de datos seleccionada
        mov dh,dl       ;cogemos la posición x en la ventana
        mov bl,3        ;Convertimos a posicion de la matrid de columnas (3 caracteres por  entrada)
        div bl
        and ax,0fh
        mov dir_mod,ax    ;lo almacenamos en dirección de memoria a modificar
        pop ax            ; recuperamos la dirección base de la fila mostrada
        add dir_mod,ax  ;Componemos la direccion completa
        mov dx,dir_mod
        mov bx,offset dato
        mov cx,1
        guarda
        ret
mod_dato endp

end DUMP