Interrupciones 2 – scroll de pantalla

Continuando con el tema, hoy vamos a explicar como hacer un scroll de una linea de la pantalla utilizando interrupciones y registros del VIC II. Primeramente vamos a hacer y explicar un ejemplo sencillo, con un scroll de una linea, caracter por caracter. Luego le agregaremos la parte de código para que se mueva de forma suave, y finalmente haremos que el scroll solo afecte a una linea de pantalla. Pero primero…

Un poco de teoría

El VIC II tiene 2 registros para realizar desplazamientos suaves de pantalla, en la dirección $D016 para el movimiento horizontal, y en $D011 para el vertical. Para nuestros ejemplos vamos a utilizar solamente el de movimiento horizontal, que según lo que dice en http://sta.c64.org/cbm64mem.html funciona de la siguiente manera:

Screen control register #2. Bits:

Bits #0-#2: Horizontal raster scroll.
Bit #3: Screen width; 0 = 38 columns; 1 = 40 columns.
Bit #4: 1 = Multicolor mode on.

Default: $C8, %11001000.

Los bits que nos interesan son el 0, 1, 2 para el movimiento fino, y el 3 para activar el modo de 38 columnas (el 4 bit lo dejamos en 0, ya que no nos interesa el modo multicolor, por ahora). Por lo que pude ver es un registro de 4 bits, no encontré para que pueden servir los bits superiores, y probando tampoco vi que hicieran algo, ya que por si bien por defecto están en $c8, si pokeamos y lo seteamos en $10 no veremos ningún cambio.

Los bits de scroll pueden tomar solo valores de 0 a 7… ¿¿¿Como haremos un scroll que mueva mas pixeles que eso???

En realidad no necesitaremos mas, ya que iremos moviendo finamente TODA la pantalla con $d016, y cuando llegamos al valor 7 RÁPIDAMENTE avanzaremos un caracter toda la linea, y ponemos el valor del registro a 0… y es todo lo que tendremos que hacer para obtener un scroll fino…
bueno, no… tendremos que hacer algunas cosas mas.

El registro de scroll fino mueve TODA LA PANTALLA, y si nosotros hacemos lo anteriormente dicho veremos que toda la pantalla va a los saltos, salvo la linea que estamos moviendo, por lo que vamos a tener que setear una interrupción que haga todo lo dicho para el scroll, y otra unas lineas mas abajo que restaure la pantalla (una imagen para aclarar mejor todo):

Ejemplo 1: Scroll por caracter con interrupciones

Para comenzar vamos a hacer una simple rutina para mover una linea, caracter por caracter. Ademas, vamos a hacer que el origen del texto lo obtenga de la primera linea de la pantalla, así podremos jugar con los textos mientras se desplazan.


BasicUpstart2(main)
.const scrollLine = $0400+22*40

* = $1000 "Main Program"

main:
sei // deshabilito interrupciones

lda #$7f // apago las interrupciones
sta $dc0d // de la CIA

lda $d01a // activo la irq
ora #$01 // por raster
sta $d01a

lda $d011 // borro el MSB de raster
and #$7f
sta $d011

lda #100 // especifico una linea de raster
sta $d012 // LSB (aca puede ser cualquiera aca)

lda #intcode // de nuestra rutina
sta 789
cli // habilito las interrupciones
rts // retorno (en este caso BASIC)

intcode:
jsr scrollChar // voy a mi rutina de scroll
inc $d019 // notifico interrupcion

lda #100 // Restauro el punto de interrupción
sta $d012 // para el proximo refresco

jmp $ea31 // salto a las rutinas del sistema

scrollChar:
{
// rutina que scrollea un caracter a la izquierda
ldx #0
loopScroll:
lda scrollLine+1, x
sta scrollLine, x
inx
cpx #39
bne loopScroll

// obtengo un nuevo caracter
textIndex: // index de la cadena q esta en $0400
ldx #0 // #0 se va a ir modificando
lda $0400 , x
sta scrollLine + 39

inx
cpx #39 // si llego al ultimo caracter
beq resetIndex // de la primera linea, reseteo el index
stx textIndex + 1 // si no incremento
rts

resetIndex:
ldx #0
stx textIndex + 1
rts
} // end scroll

Hasta la subrutina ‘scrollChar’ el programa es virtualmente idéntico al del post anterior, en el que ciclábamos los colores. Aquí en vez de rotar el color de borde vamos a llamar a una subrutina, que se llamara 60 veces por segundo, y en cada llamada hace un scroll de un caracter hacia la izquierda. La rutina funciona de la siguiente manera:

  • en un loop de 0 a 39, va copiando los caracteres, de n+1 a n (bloque que comienza en la etiqueta ‘loopScroll:’ y finaliza en ‘bne loopScroll’)
  • Toma el siguiente caracter (a partir de $0400) y lo almacena en la ultima columna
    Aquí me gustaría mostrar algo: el índice se va guardando en textIndex + 1, que corresponde al operando de la instrucción LDX, que iremos incrementando en cada llamada a la interrupción, y si llega a la columna 39 lo reseteamos a 0. Me pareció interesante y óptima esta forma de llevar el indice (en vez de utilizar una etiqueta en otra dirección de memoria, cargarla en un registro, incrementar el registro, guardar el registro actualizado en la posición de memoria… bufff). Esta forma de hacerlo se la ‘robé’ a Mike Rivera (https://www.facebook.com/thc64), quien me pidió ayuda con unas rutinas de scroll, y me gusto esta forma de llevar un índice de una cadena de texto.
  • cuando llega a la última posición de la primera linea de la pantalla resetea el índice (pone el operando de LDX en 0)

A continuación, un ejemplo funcionando (pueden descargar el código fuente y el compilado desde Github https://github.com/moonorongo/c64_tutorial_samples)

Ejemplo 2: scroll fino… con detalles

Aquí vamos a agregar una pequeña subrutina que, en cada llamada a la interrupción, desplace la pantalla 1 pixel, y cuando llega a la posición 7 (recordar que el registro solo tiene posiciones de 0 a 7) avanza un caracter y pone el registro de scroll en 0:


intcode:
jsr scrollPixel               // voy a mi rutina de scroll
inc $d019                     // notifico interrupcion

lda #0 // Restauro el punto de interrupción
sta $d012 // para el proximo refresco

jmp $ea31 // salto a las rutinas del sistema

scrollPixel:
{
ldx #7 // 38 columnas, scroll h, index scroll fino
cpx #255
beq resetScrollFino

stx $d016
dec scrollPixel + 1
rts

resetScrollFino:
ldx #7
stx scrollPixel + 1
stx $d016
jsr scrollChar
rts
}

La subrutina scrollPixel: va haciendo un ciclo de 7 a 0 (porque estamos desplazando hacia la izquierda – por eso comparamos con #255), cuando sucede eso es que seteamos $d016 en #7. A continuación, una muestra de como queda (código completo en Github https://github.com/moonorongo/c64_tutorial_samples):

UGGHH!!! Todo muy bien con el scroll, pero nos quedo todo el resto de la pantalla a los saltos… Esto es porque, como dijimos antes, tenemos que restaurar el registro de scroll para el resto de la pantalla fuera de la linea que queremos mover, lo cual haremos en el siguiente ejemplo.

Ejemplo 3 – Scroll final

Como hicimos en el capítulo anterior de interrupciones, vamos a tener un ‘modeflag’, que según su estado vamos a atender una parte u otra de la pantalla.
en ‘intcode:’ vamos a obtener el estado de ‘modeflag’ y segun el mismo vamos a ‘lineaScroll’ o ‘restauroPantalla’. En ‘lineaScroll:’ hacemos lo mismo que en el ejemplo anterior (yo acá agregue un cambio de color de fondo, para ver a partir de que linea sucede la interrupción), y fijamos el siguiente punto de interrupción.
En ‘restauroPantalla:’ pongo el color de pantalla normal, restauro el puntero de scroll a 0, establezco la próxima linea de raster y hago los pla,txa… correspondientes para retornar de la interrupción.


intcode:
    lda modeflag
    beq lineaScroll
    jmp restauroPantalla

lineaScroll:                      // viene si modeflag es 0
{

    lda #$01                      // invertimos el modeflag
    sta modeflag                  // para que la proxima vez vaya a 
                                  // la otra parte del codigo
    lda #COLOUR1                  // ponemos color 
    sta $d020
    sta $d021

    jsr scrollPixel               // voy a mi rutina de scroll

    lda #LINE1                    // seteamos nuevamente la
    sta $d012                     // linea de interrupcion
    inc $d019                     // acusamos recibo de interrupcion

    jmp $ea31                     // salto a las rutinas del sistema
}

restauroPantalla:
{
    lda #$00                      // invertimos el modeflag
    sta modeflag

    lda #COLOUR2                  // ponemos el color
    sta $d020
    sta $d021

    ldx #0                        // dejamos el scroll fijo
    stx $d016   

    lda #LINE2                    // seteamos linea de raster
    sta $d012                     

    inc $d019                     // acusamos recibo
                 
                                  // PEEERO: 
    pla                           // Aqui salimos completamente
    tay                           // esta es la forma de salir de la
    pla                           // interrupción, restaurando
    tax                           // los registros.
    pla                           // lo explico con mas detalle a continuación
    rti
}

A continuación, el resultado final:

Y esto es todo por hoy…

Los 3 ejemplos están subidos y compilados en Github (https://github.com/moonorongo/c64_tutorial_samples), cualquier duda o consulta la pueden hacer en mi Facebook https://www.facebook.com/mscifu

Hasta la próxima!

Anuncios

2 comentarios en “Interrupciones 2 – scroll de pantalla

  1. Muchísimas gracias por estos tutoriales paso a paso.
    No sabia como funcionaba BIT o más bién como aplicarlo y ahora no paro de usarlo XD.

    Prestaré muchisima atención a cuando publiques un scroll a pantalla completa.

    • Hola Maniako! El scroll a pantalla completa es más simple! Solamente tenes que hacer que la rutina que corre todos los caracteres lo haga con las 25 lineas de la pantalla (de la forma mas optima posible, je) y pones el punto de interrupción lo mas bajo posible (ej: en la línea 20), ni siquiera tenes q preocuparte por restaurar los registros de scroll, ya q es toda la pantalla. Gracias por interesarte en el tutorial!

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

w

Conectando a %s