jueves, 5 de abril de 2012

Ensamblador 8086 Modo 13h Memoria para Gráficos

El programa del post anterior pinta pixeles usando la interrupción 10h servicio 0Ch; podríamos pensar que estamos mandando la instrucción de pintar un pixel directamente a la tarjeta de video. Sin embargo, lo que realmente estamos haciendo es escribir al área de memoria de gráficos que inicia en A000:0000.

Esta área consta de 320x200 bytes (64,000 bytes) y cada byte corresponde a un pixel. Para cada byte del área de memoria de gráficos, la tarjeta de video lee el byte y usa ese byte como índice en la paleta de colores para obtener el color del pixel.

En la pantalla, el pixel superior-izquierdo (fila 0, columna 0) corresponde al byte en la dirección A000:0000, el pixel superior-derecho (fila 0, columna 319) corresponde a A000:013F, el primer pixel de la segunda fila (fila 1, columna 0) está mapeado a la dirección A000:0140. En general, el pixel en la fila i, columna j corresponde a A000:(140h*i+j).

La siguiente imagen muestra cómo interactuamos con el área de memoria y la paleta de colores; la tarjeta de video usa esta información para desplegar el contenido de la pantalla.

El siguiente programa muestra la misma funcionalidad del programa del post anterior, pero esta vez escribiendo directamente al área de memoria de gráficos.

.model small
.stack 128
.data

.code
.startup
main proc
  ; INT 10h / AH = 0 - configurar modo de video.
  ; AL = modo de video deseado.
  ;     00h - modo texto. 40x25. 16 colores. 8 paginas.
  ;     03h - modo texto. 80x25. 16 colores. 8 paginas.
  ;     13h - modo grafico. 40x25. 256 colores. 
  ;           320x200 pixeles. 1 pagina. 
  mov ax,0013h
  int 10h
  mov ax, 0A000h
  mov ds, ax  ; DS = A000h (memoria de graficos).

  ; ============== Lineas verticales ======================
  ; Queremos pintar 256 colummas, cada una con un alto de 
  ; 200 pixeles. Podemos ejecutar 51,200 ciclos.
  ; Como la memoria de graficos es lineal, es mejor pintar
  ; una fila a la vez, cada fila tiene 320 columnas, pero
  ; solo pintamos 256. Al llegar a la columna 256 saltamos
  ; a la siguiente fila sumando 320-256 = 64
  ; Cada pixel cambia de color para dar el efecto de lineas
  ; verticales
  mov cx,0C800h ; # de pixeles
  xor dx,dx     ; contador de columnas y color
  xor di,di

  ciclo_1:
  mov [di], dx ; poner color en A000:DI
  inc di
  inc dx
  cmp dx,256
  jne sig_pix1

  add di,0040h ; saltar al inicio de siguiente fila
  xor dx,dx    ; reiniciar columnas y color
  sig_pix1:
  loop ciclo_1

  ; esperar por tecla
  mov ah,10h
  int 16h

  ; ============== Lineas horizontales ======================
  ; Queremos pintar 200 filas, cada una con un largo de 
  ; 320 pixeles. Podemos ejecutar 64,000 ciclos.
  ; Despues de pintar los 320 pixeles correspondientes a
  ; una fila, cambiamos el color para pintar la siguiente
  ; fila y dar el efecto de lineas horizontales.
  mov cx,0FA00h ; todos los pixeles de la pantalla
  xor dx,dx ; color para cada fila
  xor bx,bx ; contador de columnas
  xor di,di

  ciclo_2:
  mov [di], dx ; poner color en A000:DI
  inc di
  inc bx
  cmp bx,320
  jne sig_pix2
            ; nueva fila
  xor bx,bx ; resetear contador de columnas
  inc dx    ; cambiar color
  sig_pix2:
  loop ciclo_2

  ; esperar por tecla
  mov ah,10h
  int 16h

  ; regresar a modo texto
  mov ax,0003h
  int 10h
  
  ; finalizar el programa
  mov ax,4c00h
  int 21h
  ret
main endp
end

3 comentarios:

  1. Este ejemplo pero con NASM sera que no lo tienen, les agradeceria bastante si me lo pudieran enviar

    ResponderEliminar
  2. Respuestas
    1. Muchas gracias, nos da gusto que los tips sean de utilidad. Saludos.

      Eliminar