; ----------------------------------------------------------------------------
; -      TITULO  : Caracteres ASCII COM-FASM con formato                     -
; -----                                                                  -----
; -      AUTOR   : Alfonso Víctor Caballero Hurtado                          -
; -----                                                                  -----
; -      VERSION : 1.0                                                       -
; ----------------------------------------------------------------------------

  use16 		         ; usa codigo de 16 bits
  ORG	    100h                 ; ES tipo COM
  ; Constantes
  Col1      EQU  Buffer          ; Dirección donde se encuentran los espacios
  Col2      EQU  Col1 + 1        ; Dirección para imprimir dos espacios
  Col3      EQU  Col1 + 2        ; Dirección para imprimir un Buffer
  SegVid    EQU  0B800h          ; Segmento de Vídeo en Color
  BlanNeg   EQU  7               ; Atributo blanco sobre negro
  NumCols   EQU  10              ; Número de columnas por cada fila
  ImpCad    EQU  9               ; Función imprimir cadena de INT 21h
  LeeCur    EQU  3               ; Función leer posición cursor de INT 10h
  PosCur    EQU  2               ; Función posicionar cursor de INT 10h
  ; ------------
  ; Preparamos el segmento de vídeo
  MOV       BX, SegVid
  MOV       ES, BX               ; Lo metemos en ES para STOSW
  CLD                            ; Flag de dirección nulo => di incrementa autom
  ; ------------
  XOR       BX, BX               ; Contador de columnas
  $_loop:                        ; Aquí empieza el bucle principal
    ; 1. Justificamos el número a la derecha imprimiendo espacios
    MOV     DI, Col1             ; Empezamos suponiendo que es de 3 dígitos
    CMP     [Car], 99            ; Comprobamos si el número necesita justificac
    JA      $_ImpNum             ; No hay que justificar a la derecha
    CMP     [Car], 9             ; Comprobamos si el número es < 10
    JA      $_DosDig
    MOV     DI, Col3             ; Es de 1 dígito
    JMP     $_ImpNum
    $_DosDig:
    MOV     DI, Col2             ; Es de 2 dígitos
    $_ImpNum:
    ; 2. Imprimimos el número propiamente
    MOV     AL, [Car]            ; Usamos AL para pasar Car AL proc
    CALL    WriteByte            ; Escribimos el número Car
    ; 3. Imprimimos a su lado su carácter ASCII correspondiente
    ; 3.1. Primero obtenemos la posición del cursor
    MOV     AH, LeeCur           ; Obtenemos la posición del cursor
    XOR     BH, BH               ; Página 0
    INT     10h                  ; DH fila, DL columna
    ; 3.2. Hacemos los cálculos para impresión directa del carácter
    MOV     AX, 160              ; DI = 160*Fila+2*Columna
    MUL     DH
    MOV     DI, DX
    AND     DI, 0FFh             ; Limpiamos la parte superior
    SHL     DI, 1                ; Multiplicamos por 2
    ADD     DI, AX               ; En DI tenemos la posición de la mem pantalla
    ; 3.3. Ahora posicionamos el cursor un puesto a la derecha
    INC     DL                   ; Antes de imprimir nos posicionamos 1 derecha
    XOR     BH, BH               ; Página de vídeo activa
    MOV     AH, PosCur           ; Función posicionar el cursor
    INT     10h                  ; Posicionamos el cursor
    ; 3.4. Seleccionamos el resto de valores para impresión directa
    MOV     CX, 1                ; Número de caracteres a imprimir
    MOV     AH, BlanNeg          ; Atributo
    MOV     AL, [Car]            ; AL = carácter a imprimir
    REP     STOSW                ; dec CX, metemos AX en ES:DI hasta que CX = 0
    ; 4. Imprimimos el Buffer separador de columnas
    MOV     DX, SepCol           ; Dirección al Buffer separador de columnas
    ; 4.1. Contamos las columnas
    INC     BL                   ; Incrementamos contador de columnas
    ; 4.2. Si estamos al final de la fila saltamos a la siguiente
    CMP     BL, NumCols          ; Comprobamos que no hay más de NumCols colum
    JAE     $_NxtRow             ; Si es mayor, saltamos a otra fila
    MOV     AH, ImpCad           ; Función imprimir cadena de INT 21h
    INT     21h                  ; Imprimimos el Buffer separador de columnas
    JMP     $_SgteASCII          ; No saltamos a la siguiente fila
    $_NxtRow:
    XOR     BL, BL               ; Inicializamos el contador de columnas
    MOV     DX, __CRLF           ; Metemos en DX la dirección de __CRLF
    MOV     AH, ImpCad           ; Función imprimir cadena de INT 21h
    INT     21h                  ; Saltamos al principio de la sgte fila
    ; 5. Incrementamos el contador de bytes
    $_SgteASCII:
    INC     BYTE [Car]           ; Siguiente carácter ASCII
  JNZ       $_loop               ; Mientras no superemos 255, volvemos
  MOV     AX, 4c00h              ; Servicio 4Ch, mensaje 0
  INT     21h                    ; volvemos AL DOS
; ****** Fin del programa
; ****** Aqui se pueden poner procedimientos y macros
  WriteByte:
    ; Propósito: Imprime por pantalla el número de tipo BYTE "Numero"
    ; Entrada  : Parámetros de entrada Numero y Signo
    ;            Signo  = 0 -> Numero ES sin signo
    ;            Signo <> 0 ->           con signo
    ; Salida   : Escribe Numero en pantalla
    MOV     CX, 0A00h		      ; Dividir por 10 para extraer los dígitos
    ._Bucle1:			      ; CL será el contador
      XOR   AH, AH		      ; Eliminamos el resto para poder dividir
      DIV   CH			      ; El resto:cociente está en AH:AL
      OR    AH, 30h		      ; Convertimos el número a ASCII
      PUSH  AX 	                      ; Lo guardamos en la pila
      INC   CL                        ; Incrementamos el contador de dígitos
      OR    AL, AL		      ; Comprobamos SI AL = 0
    JNZ   ._Bucle1		      ; SI no es así, volvemos
    XOR   CH, CH                      ; Limpiamos
    ._Bucle2:
      POP   AX
      MOV   [DI], AH		      ; El cociente está en la parte superior
      INC   DI			      ; Incrementamos el puntero DI
    LOOP   ._Bucle2
    MOV     DX, Buffer                ; para la INT 21h, servicio 9
    MOV     AH, ImpCad                ; Especifica el servicio de impresión
    INT     21h			      ; Invoca servicio 9
  RET

; ****** Inicio de los datos
  Car       DB    0              ; Inicializamos el contador de bytes a 0
  __CRLF    DB    13,10,'$'      ; Retorno de carro y salto de línea
  SepCol    DB    '   $'         ; Espacios separadores de columnas
  Buffer    DB    '   ', 0, '$'  ; Buffer para el número en ASCIIZ$

; Salida por pantalla:
; Caracteres ASCII desde el 0 al 255
