.MODEL    SMALL
.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:
     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           ;Poen 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 hex
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    WRITE_CHAR
     EXTRN     CURSOR_RIGHT:PROC
;-----------------------------------------------------------------------;
; Este procedimiento escribe un car cter en la pantalla usando las      ;
; rutinas del 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                                             ;
;-----------------------------------------------------------------------;
WRITE_CHAR     PROC
     PUSH AX
     PUSH BX
     PUSH CX
     PUSH DX
     MOV  AH,9           ;Llamada para imprimir car cter/atributo
     MOV  BH,0           ;Puesto para visualizar la p gina 0
     MOV  CX,1           ;Escribe s¢lo un car cter
     MOV  AL,DL          ;Car cter a escribir
     MOV  BL,7           ;Atributo normal
     INT  10h            ;Escribe el car cter y el atributo
     CALL CURSOR_RIGHT   ;Ahora pasa a la siguiente posici¢n del cursor
     POP  DX
     POP  CX
     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_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 cero 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
