

.MODEL    SMALL
 
.DATA
     PUBLIC    SCREEN_PTR
     PUBLIC    SCREEN_X, SCREEN_Y
SCREEN_SEG     DW      0B000h      ;Segmento del buffer de pantalla
SCREEN_PTR     DW      0           ;Desplazamiento del cursor dentro de la
                                   ; memoria de pantalla
SCREEN_X  DB   0                   ;Posici¢n del cursor en la pantalla
SCREEN_Y  DB   0
 
 
.CODE
 
     PUBLIC    WRITE_STRING
;-----------------------------------------------------------------------;
; Este procedimiento escribe una cadena de caracteres en la pantalla.   ;
; La cadena tiene que terminar con      DB   0.                         ;
;                                                                       ;
; A la entrada:  DS:DX Direcci¢n de la cadena.                          ;
;                                                                       ;
; Usa:           WRITE_CHAR                                             ;
;-----------------------------------------------------------------------;
WRITE_STRING   PROC
     PUSH AX
     PUSH DX
     PUSH SI
     PUSHF                  ;Salva el indicador de direcci¢n
     CLD                    ;Pone la direcci¢n para incremento (hacia adelante)
     MOV  SI,DX             ;Pone la direcci¢n en SI para LODSB STRING_LOOP:
STRING_LOOP:
     LODSB                  ;Pone un car cter en el registro AL
     OR   AL,AL             ;¨Ha encontrado ya el 0?
     JZ   END_OF_STRING     ;S¡, ya hemos terminado con la cadena
     MOV  DL,AL             ;No, escribe el car cter
     CALL WRITE_CHAR
     JMP  STRING_LOOP
END_OF_STRING:
     POPF                   ;Restablece el indicador de direcci¢n
     POP  SI
     POP  DX
     POP  AX
     RET
WRITE_STRING   ENDP
 
     PUBLIC    WRITE_HEX
;-----------------------------------------------------------------------;
; Este procedimiento convierte el byte que se halla en el registro DL   ;
; en hexadecimal, y escribe los dos d¡gitos hexadecimales en la posi-   ;
; ci¢n actual del cursor.                                               ;
;                                                                       ;
; A la entrada:  DL    El byte que se va a imprimir en la pantalla.     ;
;                                                                       ;
; Usa:           WRITE_HEX_DIGIT                                        ;
;-----------------------------------------------------------------------;
WRITE_HEX PROC           ;Punto de entrada
     PUSH CX             ;Salva los registros usados en este procedimiento
     PUSH DX
     MOV  DH,DL          ;Hace una copia del byte
     MOV  CX,4           ;Pone el nibble superior en DL
     SHR  DL,CL
     CALL WRITE_HEX_DIGIT     ;Escribe el primer d¡gito hexadecimal
     MOV  DL,DH               ;Pone el nibble inferior en DL
     AND  DL,0Fh              ;Suprime el nibble superior
     CALL WRITE_HEX_DIGIT     ;Escribe el segundo d¡gito hexadecimal
     POP  DX
     POP  CX
     RET
WRITE_HEX ENDP
 
     PUBLIC    WRITE_HEX_DIGIT
;-----------------------------------------------------------------------;
; Este procedimiento convierte los 4 bits bajos de DL en un d¡gito he-  ;
; xadecimal, y lo imprime en la pantalla.                               ;
;                                                                       ;
; A la entrada: DL Los cuatro bits bajos contienen el n£mero que se va  ;
;                  a imprimir en hexadecimal.                           ;
;                                                                       ;
; Usa:           WRITE_CHAR                                             ;
;-----------------------------------------------------------------------;
WRITE_HEX_DIGIT          PROC
     PUSH DX                  ;Salva los registros utilizados
     CMP  DL,10               ;¨Es este nibble < 10?
     JAE  HEX_LETTER          ;No, convertir en una letra
     ADD  DL,"0"              ;S¡, convertir en un d¡gito
     JMP  Short WRITE_DIGIT   ;Ahora escribe este car cter
HEX_LETTER:
     ADD  DL,"A"-10           ;Convertir en letra hexadecimal
WRITE_DIGIT:
     CALL WRITE_CHAR          ;Escribe la letra en la pantalla
     POP  DX                  ;Restablece el valor antiguo de DX
     RET
WRITE_HEX_DIGIT          ENDP
 
     PUBLIC    INIT_WRITE_CHAR
;-----------------------------------------------------------------------;
; Se necesita llamar a este procedimiento antes de llamar a WRITE_CHAR, ;
; puesto que WRITE_CHAR usa informaci¢n generada por este procedimiento.;
;                                                                       ;
; Escribe:             SCREEN_SEG                                       ;
;-----------------------------------------------------------------------;
INIT_WRITE_CHAR          PROC
     PUSH AX
     PUSH BX
     MOV  BX,0B800h      ;Pantalla de gr ficos en color
     INT  11h            ;Obtiene informaci¢n sobre el equipo
     AND  AL,30h         ;Guarda £nicamente el tipo de pantalla de v¡deo
     CMP  AL,30h         ;¨Es ‚ste un adaptador de pantalla monocroma?
     JNE  SET_BASE       ;No, es de color, por tanto usa B800
     MOV  BX,0B000h      ;S¡, es monocroma, por tanto usa B000
SET_BASE:
     MOV  SCREEN_SEG,BX  ;Salva el segmento de la pantalla
     POP  BX
     POP  AX
     RET
INIT_WRITE_CHAR          ENDP
 
     PUBLIC    WRITE_CHAR
     EXTRN     CURSOR_RIGHT:PROC
;-----------------------------------------------------------------------;
; Este procedimiento escribe un car cter en la pantalla usando las      ;
; rutinas de la ROM BIOS, de modo que los caracteres como el retroceso  ;
; sean tratados como cualquier otro car cter y aparezcan en la pantalla.;
;                                                                       ;
; Este procedimiento tiene que trabajar un poco para actualizar la      ;
; posici¢n del cursor.                                                  ;
;                                                                       ;
; A la entrada:  DL  Byte a imprimir en la pantalla.                    ;
;                                                                       ;
; Usa:    CURSOR_RIGHT                                                  ;
; Lee:    SCREEN_SEG, SCREEN_PTR                                        ;
;-----------------------------------------------------------------------;
WRITE_CHAR     PROC
     PUSH AX
     PUSH BX
     PUSH DX
     PUSH ES
     MOV  AX,SCREEN_SEG       ;Obtiene el segmento de la memoria de pantalla
     MOV  ES,AX               ;Apunta ES a la memoria de pantalla
     MOV  BX,SCREEN_PTR       ;Puntero a car cter de la memoria de pantalla
 
     MOV  DH,7                ;Usa el atributo normal
     MOV  ES:[BX],DX          ;Escribe car cter/atributo en la pantalla
     CALL CURSOR_RIGHT        ;Ahora va a la siguiente posici¢n del cursor
 
     POP  ES
     POP  DX
     POP  BX
     POP  AX
     RET
WRITE_CHAR     ENDP
 
     PUBLIC    WRITE_DECIMAL
;-----------------------------------------------------------------------;
; Este procedimiento escribe en la pantalla, en notaci¢n decimal, un    ;
; n£mero sin signo de 16 bits.                                          ;
;                                                                       ;
; A la entrada:  DX    N : n£mero sin signo de 16 bits.                 ;
;                                                                       ;
; Usa:         WRITE_HEX_DIGIT                                          ;
;-----------------------------------------------------------------------;
WRITE_DECIMAL  PROC
     PUSH AX             ;Salva los registros que se usan en el programa
     PUSH CX
     PUSH DX
     PUSH SI
     MOV  AX,DX
     MOV  SI,10               ;Divide entre 10 usando SI
     XOR  CX,CX               ;N£mero de d¡gitos puestos en la pila
NON_ZERO:
     XOR  DX,DX               ;Pone a 0 la palabra m s alta de N
     DIV  SI                  ;Calcula N/10 y (N mod 10)
     PUSH DX                  ;Pone un d¡gito en la pila
     INC  CX                  ;A¤adido un d¡gito m s
     OR   AX,AX               ;¨Es N = 0 ya?
     JNE  NON_ZERO            ;No, continuar
WRITE_DIGIT_LOOP:
     POP  DX                  ;D¡gitos en orden inverso
     CALL WRITE_HEX_DIGIT
     LOOP WRITE_DIGIT_LOOP
END_DECIMAL:
     POP  SI
     POP  DX
     POP  CX
     POP  AX
     RET
WRITE_DECIMAL  ENDP
 
     PUBLIC    WRITE_CHAR_N_TIMES
;-----------------------------------------------------------------------;
; Este procedimiento escribe m s de una copia de un car cter.           ;
;                                                                       ;
; A la entrada:   DL   C¢digo del car cter.                             ;
;                 CX   N£mero de veces que hay que escribir el car cter.;
;                                                                       ;
; Usa:            WRITE_CHAR                                            ;
;-----------------------------------------------------------------------;
WRITE_CHAR_N_TIMES     PROC
     PUSH CX
N_TIMES:
     CALL WRITE_CHAR
     LOOP N_TIMES
     POP  CX
     RET
WRITE_CHAR_N_TIMES     ENDP
 
 
     PUBLIC    WRITE_ATTRIBUTE_N_TIMES
     EXTRN     CURSOR_RIGHT:PROC
;-----------------------------------------------------------------------;
; Este procedimiento establece el atributo para N caracteres, comenzando;
; en la posici¢n actual del cursor.                                     ;
;                                                                       ;
;    CX   N£mero de caracteres que van a tener el atributo.             ;
;    DL   Nuevo atributo para los caracteres.                           ;
;                                                                       ;
; Usa:         CURSOR_RIGHT                                             ;
;-----------------------------------------------------------------------;
WRITE_ATTRIBUTE_N_TIMES       PROC
     PUSH AX
     PUSH CX
     PUSH DI
     PUSH ES
     MOV  AX,SCREEN_SEG       ;Pone ES para que apunte al segmento de pantalla
     MOV  ES,AX
     MOV  DI,SCREEN_PTR       ;Car cter que est  bajo el cursor
     INC  DI                  ;Apunta al atributo que est  bajo el cursor
     MOV  AL,DL               ;Pone el atributo en AL
ATTR_LOOP:
     STOSB                    ;Salva un atributo
     INC  DI                  ;Pasa al siguiente atributo
     INC  SCREEN_X            ;Pasa a la siguiente columna
     LOOP ATTR_LOOP           ;Escribe N atributos
 
     DEC  DI                  ;Apunta el comienzo del siguiente car cter
     MOV  SCREEN_PTR,DI       ;Recuerda d¢nde estamos
 
     POP  ES
     POP  DI
     POP  CX
     POP  AX
     RET
WRITE_ATTRIBUTE_N_TIMES  ENDP
 
 
     PUBLIC    WRITE_PATTERN
;-----------------------------------------------------------------------;
; Este procedimiento escribe una l¡nea en la pantalla bas ndose en      ;
; el formato.                                                           ;
;                                                                       ;
;    DB   {car cter, n£mero de veces que se ha de escribir el           ;
;          car cter 0.                                                  ;
; Donde {x} significa que x se puede repetir cualquier n£mero de veces. ;
; A la entrada:  DS:DX   Direcci¢n de la sentencia de datos anterior.   ;
;                                                                       ;
; Usa:         WRITE_CHAR_N_TIMES                                       ;
;-----------------------------------------------------------------------;
WRITE_PATTERN  PROC
     PUSH AX
     PUSH CX
     PUSH DX
     PUSH SI
     PUSHF                    ;Salva el indicador de direcci¢n
     CLD                      ;Pone el indicador de direcci¢n para incremento
     MOV  SI,DX               ;Mueve el desplazamiento al registro SI para LODSB
PATTERN_LOOP:
     LODSB                    ;Pone los datos de caracteres en AL
     OR   AL,AL               ;¨Es el final de los datos (0h)?
     JZ   END_PATTERN         ;S¡, regresa
     MOV  DL,AL               ;No, preparado para escribir el car cter N veces
     LODSB                    ;Pone el contador de repetici¢n en AL
     MOV  CL,AL               ;Y pone en CX para WRITE_CHAR_N_TIMES
     XOR  CH,CH               ;Pone a 0 el byte superior de CX
     CALL WRITE_CHAR_N_TIMES
     JMP  PATTERN_LOOP
END_PATTERN:
     POPF                     ;Restablece el indicador de direcci¢n
     POP  SI
     POP  DX
     POP  CX
     POP  AX
     RET
WRITE_PATTERN  ENDP
 
     END

