.MODEL    SMALL

.DATA

KEYBOARD_INPUT LABEL BYTE
CHAR_NUM_LIMIT DB      0           ;Longitud del buffer de entrada
NUM_CHARS_READ DB      0           ;N£mero de caracteres leidos
CHARS          DB      80 DUP (0)  ;Un buffer para entrada del teclado

.CODE

     PUBLIC    STRING_TO_UPPER
;-----------------------------------------------------------------------;
; Este procedimiento convierte la secuencia, usando el formato DOS      ;
; de secuencias de caracteres, a letras may£sculas.                     ;
;                                                                       ;
;    DS:DX     Direcci¢n del buffer de secuencia de caracteres.         ;
;-----------------------------------------------------------------------;
STRING_TO_UPPER          PROC
     PUSH AX
     PUSH BX
     PUSH CX
     MOV  BX,DX
     INC  BX                  ;Apunta el n£mero de caracteres
     MOV  CL,[BX]             ;N£mero de caracteres en el segundo byte del buffer
     XOR  CH,CH               ;Pone a cero el byte superior del n£mero
UPPER_LOOP:
     INC  BX                  ;Apunta al siguiente car cter del buffer
     MOV  AL,[BX]
     CMP  AL,'a'              ;Mira si es una letra min£scula
     JB   NOT_LOWER           ;No
     CMP  AL,'z'
     JA   NOT_LOWER
     ADD  AL,'A'-'a'          ;Convierte en letra may£scula
     MOV  [BX],AL
NOT_LOWER:
     LOOP UPPER_LOOP
     POP  CX
     POP  BX
     POP  AX
     RET
STRING_TO_UPPER          ENDP
;-----------------------------------------------------------------------;
; Este procedimiento convierte un car cter de ASCII (hex) en un nibble  ;
; (4 bits).                                                             ;
;                                                                       ;
;         AL   El car cter que ha de convertirse.                       ;
; Devuelve:    AL      Nibble.                                          ;
;         CF   1 si hay error, 0 si no lo hay.                          ;
;-----------------------------------------------------------------------;
CONVERT_HEX_DIGIT      PROC
     CMP  AL,'0'              ;¨Es un d¡gito legal?
     JB   BAD_DIGIT      ;No
     CMP  AL,'9'              ;A£n no est  seguro
     JA   TRY_HEX             ;Puede ser un d¡gito hexadecimal
     SUB  AL,'0'              ;Convertir d¡gito decimal en nibble
     CLC                      ;Poner a cero el indicador de acarreo
     RET
TRY_HEX:
     CMP  AL,'A'              ;A£n no est  seguro
     JB   BAD_DIGIT           ;No es hexadecimal
     CMP  AL,'F'              ;A£n no est  seguro
     JA   BAD_DIGIT           ;No es hexadecimal
     SUB  AL,'A'-10           ;Convertir hexadecimal en nibble
     CLC                      ;Poner a cero el indicador de acarreo
     RET
BAD_DIGIT:
     STC                      ;Activa el indicador de acarreo, hay
     RET                      ; un error
CONVERT_HEX_DIGIT      ENDP

     PUBLIC    HEX_TO_BYTE
;-----------------------------------------------------------------------;
; Este procedimiento convierte de hexadecimal en un byte, los dos ca-   ;
; racteres que est n en DS:DX.                                          ;
;                                                                       ;
;    DS:DX     Direcci¢n de los dos caracteres del n£mero hexadecimal.  ;
; Devuelve:                                                             ;
;    AL   Byte.                                                         ;
;    CF   1 si hay error, 0 si no hay error.                            ;
;-----------------------------------------------------------------------;
HEX_TO_BYTE    PROC
     PUSH BX
     PUSH CX
     MOV  BX,DX               ;Pone la direcci¢n en BX para direcc.
                              ; indirecto
     MOV  AL,[BX]             ;Obtiene el primer d¡gito
     CALL CONVERT_HEX_DIGIT
     JC   BAD_HEX             ;D¡gito hexadecimal err¢neo si el
                              ; indicador de acarreo est  activado
     MOV  CX,4                ;Multiplica por 16
     SHL  AL,CL
     MOV  AH,AL               ;Retiene una copia
     INC  BX                  ;Obtiene el segundo d¡gito
     MOV  AL,[BX]
     CALL CONVERT_HEX_DIGIT
     JC   BAD_HEX             ;D¡gito hexadecimal err¢neo si el
                              ; indicador de acarreo est  activado
     MOV  CX,4                ;Ahora multiplica por 16
     SHL  AL,CL
     MOV  AH,AL               ;Retiene una copia
     INC  BX                  ;Obtiene el segundo d¡gito
     MOV  AL,[BX]
     CALL CONVERT_HEX_DIGIT
     JC   BAD_HEX             ;D¡gito hexadecimal err¢neo si el
                              ; indicador de acarreo est  activado
     OR   AL,AH               ;Combina dos nibbles
     CLC                      ;Pone a cero el indicador de acarreo si no hay error
DONE_HEX:
     POP  CX
     POP  BX
     RET
BAD_HEX:
     STC                      ;Activa el indicador de acarreo si hay error
     JMP  DONE_HEX
HEX_TO_BYTE    ENDP

;-----------------------------------------------------------------------;
; Esta es una versi¢n simple de READ_STRING.                            ;
;                                                                       ;
;    DS:DX     Direcci¢n del  rea de la cadena de caracteres.           ;
;-----------------------------------------------------------------------;
READ_STRING    PROC
     PUSH AX
     MOV  AH,0Ah             ;Llamada para la lectura de teclado
     INT  21h                ;Llamada a la funci¢n del DOS para leer el teclado
     POP  AX
     RET
READ_STRING    ENDP

     PUBLIC    READ_BYTE
;-----------------------------------------------------------------------;
; Este procedimiento lee o un solo car cter ASCII, o un n£mero hexade-  ;
; cimal. Esto es s¢lo una versi¢n de prueba de READ_BYTE.               ;
;                                                                       ;
; Devuelve bytes en    AL     C¢digo del car cter (a no ser que AH      ;
;                       sea igual a 0).                                 ;
;              AH      1 si se ha le¡do un car cter ASCII.              ;
;                      0 si no se han le¡do caracteres.                 ;
;                      -1 si se ha le¡do una tecla especial.            ;
;                                                                       ;
; Usa:         HEX_TO_BYTE, STRING_TO_UPPER, READ_STRING                ;
; Lee:         KEYBOARD_INPUT, etc.                                     ;
; Escribe:     KEYBOARD_INPUT, etc.                                     ;
;-----------------------------------------------------------------------;
READ_BYTE PROC
     PUSH DX
     MOV  CHAR_NUM_LIMIT,3    ;S¢lo permite dos caracteres (m s Intro)
     LEA  DX,KEYBOARD_INPUT
     CALL READ_STRING
     CMP  NUM_CHARS_READ,1    ;Ver cu ntos caracteres
     JE   ASCII_INPUT         ;S¢lo uno, tratarlo como car cter ASCII
     JB   NO_CHARACTERS       ;S¢lo se ha pulsado la tecla Intro
     CALL STRING_TO_UPPER     ;No, convertir caracteres en may£sculas
     LEA  DX,CHARS            ;Direcci¢n de la secuencia de caracteres
                              ; que hay que convertir
     CALL HEX_TO_BYTE         ;Convertir secuencia de decimal a byte
     JC   NO_CHARACTERS       ;Error, por tanto devuelve 'no se han
                              ; leido caracteres'
     XOR  AH,AH               ;Se¤al de que se ha le¡do un car cter
DONE_READ:
     POP  DX
     RET
NO_CHARACTERS:
     XOR  AH,AH               ;Indica que no se ha leido ning£n car cter
     NOT  AH                  ;Devuelve -1 en AH
     JMP  DONE_READ
ASCII_INPUT:
     MOV  AL,CHARS            ;Carga el car cter que se ha le¡do
     XOR  AH,AH               ;Se¤al de que se ha le¡do un car cter
     JMP  DONE_READ
READ_BYTE ENDP


     PUBLIC    READ_KEY

;-----------------------------------------------------------------------;
; Este procedimiento lee una tecla del teclado.                         ;
;                                                                       ;
; Devuelve:    AL      C¢digo de Car cter (a no ser que AH = 1)         ;
;         AH   0 si ha leido un caracter ASCII                          ;
;              1 si ha leido una tecla especial                         ;
;-----------------------------------------------------------------------;
READ_KEY  PROC
     XOR  AH,AH               ;Llama a la funci¢n de lectura del teclado
     INT  16h                 ;Lee c¢digo de car cter/exploraci¢n del teclado
     OR   AL,AL               ;¨Es este un c¢digo ampliado?
     JZ   EXTENDED_CODE       ;S¡
NOT_EXTENDED:
     XOR  AH,AH               ;Devuelve unicamente el c¢digo ASCII
DONE_READING:
     RET

EXTENDED_CODE:
     MOV  AL,AH               ;Pone el c¢digo de exploraci¢n en AL
     MOV  AH,1                ;Indica c¢digo ampliado
     JMP  DONE_READING
READ_KEY  ENDP


     PUBLIC    READ_DECIMAL
;-----------------------------------------------------------------------;
; Este procedimiento coge el buffer de entrada de READ_STRING y         ;
; convierte la secuencia de d¡gitos decimales en una palabra.           ;
;                                                                       ;
;    AX   Palabra convertida de decimal.                                ;
;    CF   1 si hay error, 0 si no hay error.                            ;
;                                                                       ;
; Usa:         READ_STRING                                              ;
; Lee:         KEYBOARD_INPUT, etc.                                     ;
; Escribe:     KEYBOARD_INPUT, etc.                                     ;
;-----------------------------------------------------------------------;
READ_DECIMAL   PROC
     PUSH BX
     PUSH CX
     PUSH DX
     MOV  CHAR_NUM_LIMIT,6    ;El n£mero m ximo es cinco d¡gitos (65535)
     LEA  DX,KEYBOARD_INPUT
     CALL READ_STRING
     MOV  CL,NUM_CHARS_READ   ;Obtiene n£mero de caracteres le¡dos
     XOR  CH,CH               ;Pone a cero el byte sup. del contador
     CMP  CL,0                ;Devuelve error si no se han le¡do
                              ; caracteres
     JLE  BAD_DECIMAL_DIGIT   ;No se han le¡do caracteres, avisar
                              ; del error
     XOR  AX,AX               ;Comenzar con el n£mero a 0
     XOR  BX,BX               ;Comenzar al principio de la cadena
CONVERT_DIGIT:
     MOV  DX,10               ;Multiplicar el n£mero por 10
     MUL  DX                  ;Multiplicar AX por 10
     JC   BAD_DECIMAL_DIGIT   ;CF set si MUL ha producido
                              ; desbordamiento
     MOV  DL,CHARS[BX]        ;Obtiene el siguiente d¡gito
     SUB  DL,'0'              ;Y lo convierte en un nibble (4 d¡git.)
     JS   BAD_DECIMAL_DIGIT   ;D¡gito err¢neo si < 0
     CMP  DL,9                ;¨Es un d¡gito err¢neo?
     JA   BAD_DECIMAL_DIGIT   ;S¡
     ADD  AX,DX               ;No, a¤adirle al n£mero
     INC  BX                  ;Apunta al siguiente car cter
     LOOP CONVERT_DIGIT       ;Obtiene el siguiente d¡gito
DONE_DECIMAL:
     POP  DX
     POP  CX
     POP  BX
     RET
BAD_DECIMAL_DIGIT:
     STC                      ;Activa el acarreo para indicar el error
     JMP  DONE_DECIMAL
READ_DECIMAL   ENDP


     END
