martes, 26 de febrero de 2008

QBIQS (VI) La importancia de un bit

¿Un bit puede ser muy importante?

Pues sí, un bit puede significar la diferencia entre un comportamiento totalmente normal o un programa absolutamente descontrolado. Voy a contaros una historia que me ha sucedido con el QBIQS, espero que la encontréis divertida (aunque hasta que encontré el maldito bit no me reía).


Un programa que se dispara a sí mismo

Cuando he ido a enseñarles el juego a unos compañeros, quienes también me dan consejos y prueban la jugabilidad, han empezado a suceder cosas extrañísimas... la primera de todas que el juego reseteó el MSX. Luego, probándolo más nos dimos cuenta de que la música se desincronizaba, a veces se reseteaba todo, otras veces se quedaba colgado... pero siempre el problema estaba en la rutina de música.

Dicha rutina está basada en el replayer del PT3 originalmente programado por Sergei Bulba para Spectrum y adaptado por Dioniso para MSX. Esta rutina se automodifica para ganar velocidad, con lo que su ejecución debe ser en RAM. Me puse a examinar el código, comparándolo con la salida del ensamblador y me di cuenta de que la rutina de decodificación del PT3 había sido modificada de algún modo por otra parte del programa... concretamente ¡por un impacto de un QBIQ lanzado!

¡Hay que hacer bien las cuentas!

La única posibilidad estaba en el último cambio que había hecho cuando uno de los beta-testers del juego me dijo que los disparos iban algo lentos para su gusto. Había modificado la rutina para, en lugar a 2 pixels por frame, moverlos a 3 pixels por frame. Una vez hecho esto estaba obligado a examinar la rutina de anulación del disparo cuando éste se sale de la pantalla.

Originalmente los disparos se anulaban cuando su coordenada vertical valía -9 y yo estaba convencido de que la coordenada de origen era 179. Así que hice un cálculo rápido 179 - (-9) = 188 que no es divisible por 3, pero 189 sí lo es, así que la nueva coordenada de anulación debe ser -10 (que es $F6 en hexadecimal). Probé el disparo y funcionaba bien, así que anoté el cambio y lo di por bueno.

Sin embargo la coordenada de origen era 159, por lo que 159 - (-10) = 169 no era divisible por 3, de modo que los disparos jamás llegaban a tener la coordenada vertical igual a -10, por lo que no se anulaban. Para acelerar los cálculos existen unas tablas de desplazamiento según la coordenada vertical del disparo, pero esas tablas están pensadas para funcionar hasta el valor -15... valor que sobrepasaban los disparos.

Al aparecer coordenadas verticales para las que no estaba previsto el cálculo, los punteros para la tabla no valían y devolvían unos valores erróneos, situando el punto de impacto en una posición fuera de la zona del scroll... concretamente en el replayer del PT3.

Así que la solución ha sido volver a modificar la coordenada de anulación de los disparos, que nunca debía haber cambiado de -9 (cuyo valor en hexadecimal es $F7).

Esta es la historia de como un simple bit (encima el bit de menos peso de un byte) puede marcar la diferencia entre un comportamiento correcto y el caos.

3 comentarios:

OaBy dijo...

...aka "Cómo atentar a disparos contra tu propio código y no caer en la cuenta de ello"
"Se lo juro señor juez, mi código me obligó! Yo iba disparando hacia el vacío, y él estaba por ahí rondando..."

Fernando dijo...

Ha sido la venganza contra el player del PT3 por "tantos MSX como se ha cargado"...

Pentacour dijo...

Jejeje, vaya IA impresionante que has programado! Los enemigos son capaces de apoderarse de tu nave y disparar contra el código del programa... Bufff! ¿Correrán peligro nuestros MSX?¿Correrá peligro nuestra integridad física? Próximamente en sus mejores MSX...