Commodore 64 > Ensamblador
Assembler - Cosas que voy aprediendo
riq:
¡Hola programadores!
Esto no pretende ser un curso de assembler, ni nada parecido.
Solo quiero compartir con Uds. las cosas que voy aprendiendo mientras desarrollo un jueguito. Nada de lo que les voy a contar es nuevo... todo respecto a la c64 ya esta descubierto y bien detallado en codebase64 y otros sitios. De hecho, es de ahí de donde yo aprendo casi todo de la c64.
¿Entonces por qué hago esto si ya esta todo descubierto? Bueno, porque no todo lo que esta en codebase64 se entiende facilmente. Creo que varios artículos presuponen que uno sabe ciertas cosas, y cuesta bastante seguirlos. Y además porque tengo ganas de hacerlo :)
Yendo al grano, mi primer aprendizaje es...
Cómo hacer un IRQ estable
Si alguna vez trataron de hacer un "raster bar", o un simple scroll fino usando IRQ, habrán notado que la primer linea del raster hace "flicker"... es como que se corre a veces un poco hacia la derecha, o la izquierda y no se sabe bien porque.
Lo que aprendí estos días, es saber porqué pasa eso, y como prevenirlo y de esa manera lograr efectos que se vean bien.
Así es como se ve la intro del jueguito que estoy haciendo:
Basicamente tiene 4 IRQs (Código https://github.com/ricardoquesada/c64-the-race/blob/ec5f2f6b6ec8e1b4c4ad32ca95834af1398aead2/src/intro.s#L108 )
irq1: Pone una barrita violeta. Pone color gris de fondo. Comienza el scroll fino de arriba.
irq2: Pone una barrita violeta. Cambia los colores a negro. Termina el scroll fino.
irq3: Comienza el scroll fino de abajo y pone color gris de fondo.
irq4: Termina con el scroll fino y pone los colores a negro nuevamente.
Parece sencillo, pero para poner las barritas violetas me costó una eternidad.
El tema es que cuando uno esta dentro de una IRQ, el "raster beam" (o haz de luz... no se como se traduce) se sigue moviendo, entonces hay que cambiar los colores en los momentos justos.
( Para saber bien qué es el raster y demás recomiendo leer este articulo: http://dustlayer.com/vic-ii/2013/4/25/vic-ii-for-beginners-beyond-the-screen-rasters-cycle )
Para simplificar las cosas, vamos a asumir que tenemos una c64 PAL (no NTSC).
Del gráfico se puede ver que el raster para hacer una linea entera tarda 63 ciclos de CPU. Y lo más interesante de todo que hay momentos en los que el raster no es visible.
Y es justamente en esos momentos cuando uno tiene que cambiar el color del fondo de pantalla... porque sino el color aparece cortado.
Ejemplo: Aca la barra violeta aparece "cortada"...y es que cambié el color mientras el "raster beam" estaba por la mitad.
Entonces la teoría es sencilla: cambiar el color cuando el "raster beam" esta invisible.
Ciclos, interrupciones y demás:
Cuando uno instala una interrupción raster, uno no puede saber con exactitud cuantos ciclos fueron ejecutados por la siguiente razón:
Supongamos que tengo mi IRQ instalado, y en estoy ejecutando en mi ciclo principal un código que hace algo.
Justo en ese momento se prende mi IRQ ("raster beam" esta en la posición deseada).
El tema es que como la CPU puede estar ejecutando una instrucción, hay que dejar que se termine de ejecutar esa instrucción para que se llama a mi IRQ. Y eso consume ciclos.
Y como hay instrucciones de hasta 7 ciclos, cuando se llama a mi IRQ yo no se cuantos ciclos entre 0 y 7 se ejecutaron de más.
Y es exactamente por este motivo que a veces los raster bars o efectos hacen "flicker"... ya que a veces estan corridos 0, 1, ... y hasta 7 ciclos hacia la "derecha".
Lo que aprendí es que hay varias técnicas para hacer el raster estable: http://codebase64.org/doku.php?id=base:making_stable_raster_routines
Pero la que yo estoy usando en la intro es la "doble IRQ": Basicamente uso una IRQ para lograr que la CPU esta ejecutando un NOP cuando se produzca la siguiente IRQ. Eso se logra poniendo varios NOPs dentro de la primera IRQ, y luego nunca volver (no usar "rti"). De esa manera me garantizo que solo va a haber entre 0 y 1 ciclos de diferencia (y no hasta 7 como antes)... y luego ese ciclo de "sobra" se arregla con una comparación.
Los detalles están aca: http://codebase64.org/doku.php?id=base:stable_raster_routine Si alguien no entiende algo de la técnica "Doble IRQ" con gusto lo explico.
Y eso... basicamente para poner esas 2 barras violetas, tuve que aprender a usar la "doble IRQ" y contar ciclos :)
Maniako:
En su momento jugué con el raster pero no a ese nivel.
Muchas gracias por colgar el código. Ahora toca estudiarlo. ;)
A ver si me animo a colgar algunas rutinas útiles para noveles como yo.
josepzin:
Este hilo va a ser MUY interesante :)
riq:
Las famosas "bad lines"
¿Qué carajo son las "bad lines"?
Algo que molesta mucho, pero al parecer se pueden hacer trucos muy buenos abusando de estas. Pero vamos a lo que nos importa:
Antes dije que el raster beam tardaba 63 ciclos en recorrer una linea de pantalla horizontalmente. Y eso sigue siendo verdad... pero cada 8 lineas, el VIC se consume como 40 ciclos para leer los punteros a los caracteres de esa linea. O sea que no siempre tenemos 63 ciclos por "raster line".
El algoritmo es:
--- Código: ---// pseudo code
// puede que tenga que compara con 7 o 5 en vez de con 0... no hice muchas pruebas aún.
if (($d012 & scroll_fino_vertical) ==0)
tengo_23_ciclos();
else
tengo_63_ciclos();
--- Fin del código ---
¿y por qué molestan las Bad Lines? Basicamente si yo quiero cambiar el color de fondo en cada "raster line", lo que tengo que hacer es:
1) cambiar color
2) consumir los ciclos necesarios hasta llegar a 63
3) comparar si es el último color
4) si no, volver a 1)
Pero eso no funciona con las bad lines, porque cada 8 lines, solo tengo alrededor de 20 ciclos. Esto es lo que pasa:
Como pueden ver, cada 8 lineas, se desfasa todo porque estoy consumiendo 63 ciclos en vez de ~20.
Intenté comparar si estaba en una bad-line, y consumir solo ~20 ciclos... pero no me daban los ciclos ya que cada instrucción consume ciclos, y hacer todo ese calculo era muy caro.
Así que probé una rutinita distinta. Algo asi como esto:
--- Código: --- ; los ciclos consumidos estan a la derecha
; raster bars
ldx #0
: lda $d012 ; +4
cmp $d012 ; +4
beq *-3 ; +2
; wait for new raster line, change color then
lda raster_colors,x ; +4
sta $d021 ; +4
inx
cmp #$ff
bne :- ; +3
--- Fin del código ---
Y casi funciona bien...
Pero si prestan atención cada 8 lineas se repite una linea (las malditas bad lines). Mucho mejor que el test anterior, pero molesto aún.
Todavía no se como solucionar este problema... lo que hice, es que en vez de modificar el color en cada linea, lo modifica cada 2, y así esta todo uniforme.
El código para dibujar cada 2 lineas es muy similar al anterior:
--- Código: --- ; raster bars
ldx #0
: lda $d012 ; +4
clc ; +2
adc #$02 ; +2
cmp $d012 ; +4
bne *-3 ; +2
; wait for new raster line, change color then
lda raster_colors,x ; +4
sta $d021 ; +4
inx ; +2
cmp #$ff ; +2
bne :- ; +3
--- Fin del código ---
El resultado final en la intro es algo así:
La última versión del PRG siempre la van a poder bajar de aca: https://www.dropbox.com/s/x2grp14do6w4jyb/therace.prg?dl=0
Y el código fuente siempre va a estar aca: https://github.com/ricardoquesada/c64-the-race
Muy buena información sobre las "bad lines" se puede encontrar aca: http://www.zimmers.net/cbmpics/cbm/c64/vic-ii.txt
josepzin:
No tenía ni pero ni idea de esto...
Navegación
[#] Página Siguiente
Ir a la versión completa