Ensamblador
5
- Realizar un programa que guarde el estado de la pantalla con todos sus caracteres, después
rellene toda la pantalla con '*' y por último vuelva a dejar la pantalla como estaba:
;------------------------------------------------------------------------------
;Programa que guarda el estado de la pantalla con todos sus caracteres, despues
;rellena toda la pantalla con '*' y por ultimo vuelve a dejar la pantalla como
;estaba
;------------------------------------------------------------------------------
PANTALLA equ 0B800h
;------------------------------------------------------------------------------
;Definicion del segmento de datos
;------------------------------------------------------------------------------
DATOS SEGMENT
pantalla_bak db 80*25*2 DUP(?) ;Reservar una variable para guardar toda la
;informacion de la pantalla
DATOS ENDS
;------------------------------------------------------------------------------
;Definicion del segmento de pila
;------------------------------------------------------------------------------
PILA SEGMENT STACK "STACK"
db 40h dup(0)
PILA ENDS
;------------------------------------------------------------------------------
;Definicion del segmento extra
;------------------------------------------------------------------------------
EXTRA SEGMENT
RESULT DW 0,0
EXTRA ENDS
;------------------------------------------------------------------------------
;Definicion del segmento de codigo
;------------------------------------------------------------------------------
CODE SEGMENT
assume DS:datos, CS:code, SS:pila
START:
mov ax,PANTALLA
mov ds,ax
xor si,si
mov ax,datos
mov es,ax
lea di,pantalla_bak ;Apuntar a la variable
mov cx,80*25*2 ;Numero de bytes que tenemos que copiar
cld ;Direccion para incrementar DI y SI
backup:
movsb ;Mover el contenido de la direccion de memoria apuntada
;por SI a la apuntada por DI, en este caso la variable
;pantalla_bak
loop backup
mov cx,80*25 ;
xor bx,bx ;
mov al,'*' ;
mov ah,70h ;Llenar la pantalla de '*'
llena:
mov [bx],ax
inc bx
inc bx
loop llena
push ds ;
push es ;
pop ds ;
pop es ;Intercambiar DS y ES
xor di,di
lea si,pantalla_bak
xor ah,ah ;
int 16h ;Esperar a que se pulse una tecla
mov cx,4000 ;Los 4000 bytes de la pantalla
restaura: ;
movsb ;
loop restaura ;Volver a dejar la pantalla como al principio
mov ax,4C00h
int 21h
CODE ENDS
END START
- Realizar un programa que devuelva la primera posición en que se ha
encontrado un carácter dado:
;------------------------------------------------------------------------------
;Devuelve la primera posicion en que se ha encontrado el caracter a buscar
;------------------------------------------------------------------------------
CARACTER equ 'v'
;------------------------------------------------------------------------------
;Definicion del segmento de datos
;------------------------------------------------------------------------------
DATOS SEGMENT
mensaje db "www.victorsanchez2.net"
msg_caracter db "El caracter: "
msg_posicion db "Se encuentra en la posicion: "
DATOS ENDS
;------------------------------------------------------------------------------
;Definicion del segmento de pila
;------------------------------------------------------------------------------
PILA SEGMENT STACK "STACK"
db 40h DUP(0)
PILA ENDS
;------------------------------------------------------------------------------
;Definicion del segmento extra
;------------------------------------------------------------------------------
EXTRA SEGMENT
RESULT DW 0,0
EXTRA ENDS
;------------------------------------------------------------------------------
;Definicion del segmento de codigo
;------------------------------------------------------------------------------
CODE SEGMENT
assume cs:code,ds:datos,es:extra,ss:pila
START PROC
;Inicializamos los registros de segmento
mov ax,datos
mov ds,ax
mov ax,pila
mov ss,ax
mov ax,extra
mov es,ax
;Limpiamos la pantalla
mov ax,0B800h ;En esta direccion comienza la memoria de video
mov es,ax ;Lo cargamos en el segmento extra
xor di,di ;Ponemos DI=0
mov cx,80*25 ;80 lineas x 25 columnas
xor al,al ;0=" " Rellenar la pantalla con blancos
mov ah,0Fh ;Fondo negro, letras blancas
rep stosw
lea si,mensaje ;Cargar el mensaje donde buscaremos
mov al,CARACTER ;Cargar el caracter a buscar
mov cx,22 ;Longitud maxima para buscar (longitud de 'mensaje')
call busca_fin ;Buscar la posicion en que se encuentra el CARACTER
mov ax,0B800h ;
mov es,ax ;Colocarnos al inicio de la memoria de video
add cl,30h ;Preparar CL para mostrar el caracter por pantalla
push cx ;Guardarlo para recuperarlo despues
mov di,(80*2)*2 ;Colocarnos en la segunda fila
lea si,mensaje ;Colocar el offset de mensaje en si
mov cx,22 ;Total de caracteres de mensaje
call pinta ;Mostrarlo por pantalla
mov di,(80*4)*2 ;Nos colocamos en la cuarta fila
lea si,msg_caracter ;Cargar el offset
mov cx,13 ;Total de caracteres de mensaje
call pinta ;Mostrarlo por pantalla
mov di,(80*4+13)*2 ;Colocarnos al final del msg_caracter
mov byte ptr es:[di],CARACTER ;Mostrar el CARACTER por pantalla
mov di,(80*5)*2 ;Ponernos en la quinta fila
lea si,msg_posicion ;Cargar el offset
mov cx,29 ;Total de caracteres de mensaje
call pinta ;Mostrarlo por pantalla
mov di,(80*5+29)*2 ;Colocarnos al final del msg_posicion
pop cx ;Recuperar la posicion en que se encontraba CARACTER
mov es:[di],cl
mov ax,4C00h ;
int 21h ;Terminar el programa
START ENDP
;------------------------------------------------------------------------------
; busca_fin
;
; in: AL contiene el caracter que debemos buscar
; SI contiene la cadena que debemos buscar
; out: En CX se guarda la posicion donde se ha encontrado el caracter
; machaca: CX
; make: Devuelve en CX la primera posicion donde se ha encontrado el caracter
; dado en AL
;------------------------------------------------------------------------------
busca_fin proc near
push di
push dx
push es
push si
push ax
mov ax,ds ;
mov es,ax ;
mov di,si ;Copiar DS:SI en ES:DI
mov dx,cx ;Copiar el limite en otro registro
cld ;Direccion incremental
pop ax ;Recuperar el caracter que nos han pedido
push ax ;Guardarlo en la pila para no perderlo
repnz scasb ;Buscar el caracter pedido
sub dx,cx ;Calcular la longitud
mov cx,dx ;Guardar la longitud en CX
pop ax
pop si
pop es
pop dx
pop di
ret
busca_fin endp
;------------------------------------------------------------------------------
; pinta
;
; in: SI contiene el offset del mensaje a mostrar
; DI contiene la direccion donde se ira mostrando el mensaje
; CX contiene el numero de iteraciones a realizar
; out:
; machaca: CX
; make: Muestra por pantalla el mensaje dado
;------------------------------------------------------------------------------
pinta proc near
push ax
push si
push di
mov ah,0Fh ;Fondo negro y letras blancas
pintar: ;
mov al,[si] ;
mov es:[di],ax ;
inc si ;
inc di ;
inc di ;
loop pintar ;Mostrarlo por pantalla
pop di
pop si
pop ax
ret
pinta endp
CODE ENDS
END START
- Hacer un programa que muestre la sucesión de códigos ASCII en la esquina superior
derecha de la pantalla, intercambiando los caracteres cada medio segundo. Este programa ya es algo más
complejo que los anteriores ya que empezamos a trabajar con programas residentes y el RTC. Os recomiendo que
aprendais bien las características de los programas residentes y programación del RTC antes de
intentar comprender este ejercicio por completo. Este tipo de ejercicios van un nivel más allá,
y si de verdad no comprendeis bien este tipo de ejercicios es mejor que os cojais libros, apuntes o lo que sea
y lo domineis con soltura.
Un comando que os puede servir de ayuda es:
MEM /C
Con este podemos saber los programas que hay residentes en nuestra memoria. Al escribir esto veremos
como aparece el programa de nombre ASCII, que ocupa 0,4K.
Para ensamblar y ejecutar este programa, al ser .COM, hay que hacerlo con unas banderas distintas:
C:\>tasm archivo
C:\>tlink /t archivo
C:\>archivo
;------------------------------------------------------------------------------
;Programa que muestra la sucesion de codigos ASCII en la esquina superior
;derecha de la pantalla, intercambiando los caracteres cada medio segundo
;------------------------------------------------------------------------------
PANTALLA equ 0b800h
;------------------------------------------------------------------------------
;Definicion del segmento de codigo
;------------------------------------------------------------------------------
CODE SEGMENT
assume CS:code
org 100h ;Dejar las 100h primeras posiciones para el PSP
START:
jmp instalar ;Bifurcar a la rutina de instalacion
letras proc far
push ax ;
push es ;
push di ;Guardamos los registros en la pila
mov al,0Ch ;
out 70h,al ;
in al,71h ;Leer el RTC
mov ax,PANTALLA
mov es,ax
mov di,79*2
mov ax,es:[di] ;Guardamos en AX lo que hay en la esquina
inc al ;Pasamos al siguiente caracter
mov es:[di],ax ;Lo mostramos por pantalla
cli ;Inhabilitar las interrupciones
mov al,20h
out 20h,al
out 0A0h,al
sti ;Habilitar las interrupciones
pop di ;
pop es ;
pop ax ;Recuperar los registros
iret
letras endp
instalar proc far
cli ;Inhabilitar las interrupciones
xor ax,ax ;
mov es,ax ;Poner a 0 ES
mov es:[70h*4],offset letras ;Guardar el offset
mov es:[70h*4+2],cs ;y el segmento de la rutina
in al,0A1h ;Leer el PIC esclavo
and al,11111110b ;
out 0A1h,al ;Activamos IR0
in al,21h ;Leer el PIC maestro
and al,11111011b ;
out 21h,al ;Activado
mov al,0Ah ;Vamos a escribir en el registro A del RTC
out 70h,al ;
mov al,2Fh ;Los simbolos se intercambian cada medio segundo
out 71h,al ;Lo indicamos en el registro A del RTC
mov al,0Bh ;Vamos a escribir en el registro B del RTC
out 70h,al
in al,71h
or al,01000000b ;
out 71h,al ;Activamos las interrupciones periodicas
sti ;Habilitar las interrupciones
lea dx,instalar
int 27h
instalar endp
CODE ENDS
END START
- Algo muy importante es el programa que sirve para desinstalar y restaurar todo lo que hizo el programa
anterior. Si no lo hacemos seguirá mostrándose la sucesión de los caracteres ASCII mientras
mantengamos encendido el ordenador. Después de ensamblar y ejecutar el programa con:
C:\>tasm /zi archivo
C:\>tlink /v archivo
C:\>archivo
Este programa no es .COM, por lo tanto usamos las banderas habituales. Después de ejecutarlo, si volvemos
a escribir "MEM /C" veremos que nuestro programa ha desaparecido, ya no se encuentra residente en memoria.
;------------------------------------------------------------------------------
;Desactiva las interrupciones periodicas del RTC y elimina el programa anterior
;de la memoria.
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
;Definicion del segmento de pila
;------------------------------------------------------------------------------
PILA SEGMENT STACK "STACK"
DB 40h dup(0)
PILA ENDS
;------------------------------------------------------------------------------
;Definicion del segmento extra
;------------------------------------------------------------------------------
EXTRA SEGMENT
RESULT DW 0,0
EXTRA ENDS
;------------------------------------------------------------------------------
;Definicion del segmento de codigo
;------------------------------------------------------------------------------
CODE SEGMENT
ASSUME CS:CODE,SS:pila
START PROC FAR
call desinstalar
mov ax,4C00h ;
int 21h ;Terminar el programa
START ENDP
;------------------------------------------------------------------------------
; desinstalar
;
; in:
; out:
; machaca:
; make: Desinstala las interrupciones periodicas (PIE), desconecta la
; interrupcion del RTC al PIC esclavo, restaura los vectores de
; interrupcion y desinstala el programa residente
;
;------------------------------------------------------------------------------
desinstalar PROC
push ax
push es
push ds
cli ;Inhabilitar las interrupciones
;Antes de proceder a desinstalarlo comprobamos si existe
cmp word ptr es:[70h*4],0
je FIN
mov al,0Bh ;Registro B del PIC
out 70h,al ;
and al,10111111b ;
out 71h,al ;Deshabilitamos las interrupciones periodicas (PIE)
in al,0A1h ;Leer el PIC esclavo
OR al,00000001B ;
out 0A1h,al ;desconectamos la interrupcion del RTC al PIC esclavo
;Restaurar los vectores de interrupcion
xor ax,ax
mov es,ax
mov ax,es:[70h*4+2] ;Copia en DS el segmento de codigo del
mov ds,ax ;programa a desinstalar
xor ax,ax
mov es:[70h*4],ax ;Poner el offset a 0
mov es:[70h*4+2],ax ;Poner CS a 0
;Desinstalar el programa residente
mov ax,ds:[2Ch] ;
mov es,ax ;
mov ah,49h ;
int 21h ;Desinstalar el PSP
mov ax,ds ;
mov es,ax ;
mov ah,49h ;
int 21h ;Desinstalar CS
sti ;Habilitar las interrupciones
FIN: pop ds
pop es
pop ax
ret
desinstalar ENDP
CODE ENDS
END START
|
|