.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
;-----------------------------------------------------------------------;
; Este procedimiento imprime un car cter en la pantalla usando la lla-  ;
; mada de funci¢n del DOS. WRITE_CHAR cambia los caracteres de 0 a 1Fh  ;
; por un punto.                                                         ;
;                                                                       ;
; A la entrada:  DL    El byte que se va a imprimir en la pantalla.     ;
;-----------------------------------------------------------------------;
WRITE_CHAR     PROC
     PUSH AX
     PUSH DX
     CMP  DL,32          ;¨Est  el car cter delante de un espacio?
     JAE  IS_PRINTABLE   ;No, impirimir tal cual
     MOV  DL,'.'         ;S¡, sustituir por un punto
IS_PRINTABLE:
     MOV  AH,2           ;Llamada para escribir un car cter
     INT  21h            ;Escribe el car cter contenido en el registro DL
     POP  DX             ;Restablece el valor antiguo de AX y DX
     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
