Blog | Archivo | Contacto | Administración |
En algún momento tenía que dar el paso y hacer algo de software para PcW16; aprovechando las vacaciones y que tenía relativamente fresco el port del Knight Lore a PCW me pareció el momento adecuado. Es una máquina bastante más puñetera, pero bastante más potente.
Análisis:
Utilizando de nuevo como base la versión de CPC, el Knight Lore entra en 48 KB + 16 KB de memoria de vídeo, mucho más fácil para empezar que la Abadía o el Hero Quest.
Desgraciadamente, el PcW16 no tiene un modo de paginado que separe lecturas de escrituras (modo ANT), lo cual complica el parcheo: en el caso de PCW pongo en lectura una página sobre la de escritura de vídeo, dándome 16 KB extras para mis parches y tablas para acelerar, cargador, roller, etc.
Otra complicación es el teclado; al contrario que la mayoría de ordenadores de 8 bits no se leen las filas / semifilas en ciertos puertos / rangos de memoria, sino que funciona como un PC (una especie de puerto serie e interrupciones).
Por el lado positivo, el vídeo es más normal. De hecho, puedo colocarlo de la misma forma que en un CPC, con entrelazado y desperdicio de memoria incluido. Sin embargo, manteniéndolo sin entrelazar y seguido me simplifica las rutinas de volcado y me deja espacio para meter algunas de mis cosas al final.
Entorno:
Para hacer pruebas rápidas es muy cómodo usar las opciones -Y y -@ del emulador, para colocar los datos / código que quiera en la memoria y definir el mapeo y punto de entrada respectivamente. De esta forma puedo probar sin tener que hacer imágenes de disco ni crear un cargador, y puenteo completamente el sistema operativo (no hay que esperar que arranque, seleccionar la opción de ejecutar programa externo, etc.).
El resto sigue siendo similar a mi entorno de desarrollo habitual para PCW: Notepad++, Pasmo y ficheros .bat para automatizar todo. Al tener que trabajar con discos con sistema FAT añado mtools a la lista de aplicaciones.
Memoria:
Primero vamos a reservamos las 64 KB que necesitamos. No es necesario que sean contiguas, y sólo es necesario que la de vídeo esté por debajo de las primeras 256 KB. Aun así, las elijo consecutivas 4-5-6-7, y uso la 3 para el cargador, la roller (no puede estar en otro sitio en el PcW16) y los parches que no me entren en la zona principal.
Al igual que el port de PCW, la sitúo en el marco $C000-$FFFF, en el mismo sitio que la memoria de vídeo. Afortunadamente, las rutinas de vídeo parcheadas nos entran en la memoria principal en este caso, con lo que no hay problema. Al contrario que en PCW, nos toca paginar y despaginar cada vez que se llame a una de dichas rutinas, con especial cuidado de las interrupciones (que a su vez llaman a rutinas de esa área).
Video:
Lo más fácil de todo, al contrario que en PCW: en la roller podemos escoger dónde comienza cada fila de vídeo, con una granularidad de 16 bytes. Y en cada palabra de la misma tenemos además 2 bits para indicar el modo de vídeo de dicha fila.
Una curiosidad del PcW16 es que tiene los modos de video del CPC. Normalmente está en “modo 2”, pero con más del doble de filas (imagen “casi” VGA progresiva, 640x480). En este caso, usamos el modo 1 para tener 320 en horizontal con 4 colores.
Como ya he contado, la memoria va seguida y sin entrelazar. Además, las filas están dobladas (tenemos 480 en vez de 192) y con la misma vacía arriba y abajo repetida para hacer de borde en las 80 restantes.
El formato de pixeles no es el mismo que en el caso del CPC, pero es el mismo que en el caso del PCW y PCW en color, así que trabajo de conversión ahorrado.
Paleta:
Además de los modos de vídeo, también tiene el mismo sistema de paleta triestado, para un total de 27 colores distintos (aunque con diferentes valores). Sin embargo, en un PcW16 sin modear conecta sólo la componente verde al monitor monocromo, con lo cual sólo tenemos 3 tonos de gris.
No es un problema, pues en el port de PCW ya lo tuve en cuenta para el parcheo en modo mono; al fin y al cabo, un patrón %10101010 se ve igual que uno %01010101 en el monitor monocromo, pese a ser “4 pixeles de colores distintos”. Aprovechamos esa parte y es aún más sencillo, pues no hay que modificar tablas y se puede hacer directamente con la paleta, haciendo que el color 2 sea igual al 3 para que tenga más contraste en el área de juego.
Sonido:
En este caso, aprovecho la interfaz AY por el puerto paralelo para PcW16 que hice y que además tengo implementada en el emulador. A ver si saco un rato para hacer placas como Dios manda de la misma. Hereda la interfaz de joystick y DAC de la versión para PCW.
Básicamente, se usan los 8 bits de datos del puerto de forma bidireccional junto con otras 3 señales para control (lectura / escritura, datos / latch, acceso). Pero las rutinas son prácticamente las mismas.
Aprovechando que tengo que regular la velocidad del juego hago que suene el tempo de la música como en el Spectrum, un poco más despacio que en CPC (la cual me parece bastante atropellada).
Velocidad:
El PcW16 tiene un núcleo Z80 de NEC integrado en su ASIC, funcionando a unos 16 Mhz y con una contención más relajada que el CPC, lo que hace que sea aproximadamente unas 4 veces más rápido. Esto significa que el juego sin compensar es demasiado rápido.
En vez de compensar con una pausa fija en cada “fotograma” del juego, aprovechamos el sistema de compensación de velocidad por sprites no dibujados del propio juego, calibrándolo. De esta forma, logramos una velocidad casi constante independientemente de la carga gráfica. Es algo muy sencillo de implementar en este caso, pero requiere conocer el funcionamiento interno del juego.
Interrupciones:
Aquí empezamos a meternos en temas escabrosos. El PcW16 tiene en parte una arquitectura de PC; en concreto, tiene un SuperIO como los que se ponían en placas de la época. Todos sus IRQs se enrutan al ASIC, el cual genera una interrupción del Z80 en el momento que exista alguna, sea interna (video, teclado) o externa (serie 1 y 2, paralelo, disco, IDE / externo).
Afortunadamente, las externas pueden deshabilitarse (mayormente) en el SuperIO por separado, pero la existencia de la interrupción de teclado nos obliga a cambiar la lógica del gestor del juego. Además, la frecuencia de las de vídeo es de 3 por fotograma (60 Hz) en vez de 6 por fotograma (50 Hz).
Ya que comprobamos más de una cosa en el gestor, comprobamos además el botón de encendido del PcW16; si se pulsa, hacemos un warm start (además hemos conservado la página 0 de RAM), volviendo al SO.
Teclado:
Cada vez que hay al menos una tecla en el buffer del teclado, ésta se envía vía protocolo PS/2 al ASIC, dentro del cual hay un registro de desplazamiento. Cuando se recibe un byte, se genera la interrupción correspondiente y debe ser leído. Para perder la menor cantidad de tiempo, se almacena en una tabla de pulsaciones por código de tecla.
Una vez se llama a la rutina que lee las semifilas, se llama a un parche que traduce a scancodes set 2 de PC, lee las teclas correspondientes y conforma el byte. Además, si la semifila corresponde al joystick hace la lectura correspondiente del AY (a través del puerto paralelo como vimos).
Mandar de vuelta datos al teclado es un jaleo importante en el caso del PcW16, pero afortunadamente no es algo que vayamos a hacer en este juego.
Por último, y al igual que en la versión de PCW, le añado los cursores (es cómodo jugar con ellos) y el espacio como teclas de control.
Cargador:
Finalmente, con todo funcionando, hay que hacer un cargador para que el juego cargue de forma externa desde un disco. En contra de lo que alguna gente piensa, el PcW16 es capaz de ejecutar programas de forma externa.
Basta crear un fichero de hasta 16KB con extensión PRG que se carga en $4000 y ejecuta en $4100. Esos primeros bytes pueden contener lo que se quiera, pero serán machacados en memoria en el caso de la carga desde disco.
Básicamente, se reserva memoria, se cargan los datos y se muestra un diálogo para escoger monocromo o color (con el mod correspondiente, y apagando la pantalla integrada). A partir de ahí se toma el control, anula las interrupciones que genera el ratón, se pone todo en su sitio, y lanza el juego.
Fin:
Quedan cosas menores que no merece la pena casi ni mencionar, como la anulación del flag de interrupciones, saltar la inicialización de las tablas (las pongo directamente y no cambian; además, así ganamos el espacio de esa rutina para parches), las optimizaciones que hice para PCW (como la reflexión con tablas), etc.
Otra cosa que he tenido en cuenta a la hora de generar el fichero .dsk ha sido el crearle un interleave 2:1, que acelera la carga casi 10 veces. No entiendo como los discos formateados en la propia máquina no tienen esto en cuenta.
En cualquier caso, espero que disfrutéis este juego, posiblemente el primero nativo para PcW16.
Hamor
Es la frase que más te repito, ¿no? MUCHAS, MUCHAS GRACIAS, MUCHÍSIMAS (¡denme mayúsculas más grandes!)
Amazing stuff, looking forward to it. Could you give some details about your toolchain & bat files ? Thanks !!
Ahí dando de comer a maquinas hambrientas!
Me imagino a Habi en un parque rodeado de PCWs lanzando bytes
Añadir comentario