8 años atrás
lun feb 15 2016, 05:50
Revivo este tema, porque volvi a desarrollar algo para Commodore, en este caso para C64.
Hace tiempo que estaba buscando la manera de que el sintetizador de voz sirviera para algo mas que programas en BASIC, cuando diseñe la placa, la pense para que pudiera usarse con el puerto RS232 implementado en la ROM de las Commodore y que se conecta al puerto del usuario. Los parametros de OPEN para abrir el puerto varian levemente entre maquinas, no son los mismos para C64/128 que para C16 o Plus/4, y supongo que tambien difieren en VIC20, sin embargo, la conexion electrica es la misma, ya que Commodore se aseguro de que un modem funcionara de forma directa en todos los modelos. Esto implica que al diseñar la placa del sintetizador de una manera compatible con el puerto RS232 de Commodore, me aseguraba que la misma se pudiera usar en toda la linea.
Pero si bien la diferencia entre modelos no implica un cambio de placa, si requiere algunos ajustes a la parte del soft y a la configuracion de la velocidad de comunicacion con el PIC.
Como dije, los parametros para abrir el puerto RS232 difieren levemente, pero una vez hecho esto ya se hace todo de manera similar en cualquier modelo.
El otro cambio tiene que ver con la velocidad de transmision que permite el hard de cada maquina. En C64 no se suele usar mas de 1200 bps, porque tanto la transmision como la recepcion estan implementadas por soft, y hay un limite en el proceso que se puede dedicar a esto mientras se tiene activada la pantalla. Para C64 existe una solucion intermedia, que usa en parte hard y en parte soft, es la interfaz UP9600 y su correspondiente driver, que permiten enviar y recibir a 9600 bps sin hard adicional. La desventaja es que utiliza otros pines del puerto del usuario para aprovechar los conversores paralelo-serie y serie-paralelo de las CIA.
Estuve considerando un tiempo adoptar esta conexion, pero esto implicaba que habia dos opciones con respecto a la placa: podiamos hacer una placa para C64 y otra para C16-Plus/4, o complicar el diseño para que soporte los dos tipos de conexion (UP9600 en C64 y RS232 estandar de Commodore en los otros modelos).
El problema de adoptar el estandar UP9600, es que esta es una mejora especifica de C64, que no funcionaria en Plus/4, mientras que usando la conexion RS232 estandar, funcionaria tanto en C64 (aunque a solo 1200 bps) como en Plus/4, que gracias a que tiene un chip de comunicaciones, puede enviar y recibir a hasta 19200 bps.
Como no pude decidirme a abandonar la compatibilidad de hard, solo quedaba una opcion: mejorar la velocidad de transferencia en C64. Se me ocurrio que no necesitamos enviar tantos bytes por segundo al sintetizador, pero si necesitamos usar la menor cantidad de tiempo posible en el envio, para que esto se pueda integrar en un juego en asm, de forma de que sobre proceso para un juego promedio.
La idea es enviar los comandos al sintetizador, de a 1 byte por cada cuadro del video, lo que deberia ser suficiente para mensajes hablados. Hay que tener en cuenta que el chip tiene un buffer, por lo que no importa a que velocidad se envie, siempre que haya otro comando en el buffer cuando se termina de procesar el anterior.
Para que esto funcionara, habria que sincronizarse con el inicio del borde inferior de la pantalla, ya que durante los bordes el VIC no interrumpe al 6510 y por lo tanto se puede ejecutar codigo con tiempos muy precisos. Esto no es problema porque el VIC permite generar una interrupcion en la linea de video que nos convenga.
El inconveniente mas grande es la velocidad, a 19200 bps un byte tarda casi 521 microsegundos en enviarse, que no esta mal pero puede ser demasiado para algunos juegos, teniendo en cuenta que es aqui donde se suele ejecutar el codigo de un reproductor de ".sid", y se necesita poder ejecutar todo antes de que termine el borde superior del siguiente cuadro de la imagen.
A 1200 bps la cosa es peor, un byte tarda en enviarse 8,3 milisegundos, cerca de la mitad del tiempo total entre dos cuadros.
La duda que tenia era si se podia enviar mas rapido, y como el sintetizador solo dispone de una velocidad mas rapida que 19200 bps, esa era la unica opcion posible: enviar a 57600 bps.
El fin de semana puse manos a la obra, busque todo el material tecnico, el ensamblador ACME, y como referencia viejos programas que habia hecho hace unos años, porque ya hacia tiempo que no programaba en asm de 6502.
Hecha toda la investigacion, ayer hice varias rutinas que tenian que cumplir con una condicion: el tiempo de envio de un bit debia ser de 17 microsegundos, sin importar si era un 0 o un 1. Habia leido que hubo gente que logro recibir a 57600 bps, por lo que al menos sabia que tendria que ser posible enviar a esa velocidad.
Despues de varias versiones que ni siquiera llegue a probar, porque ya no daban los tiempos en papel (o mas bien pantalla), pude lograr una rutina que cumplia con exactitud el requisito, 17 microsegundos por bit, sin tener que usar codigo automodificable o precalcular valores. Ni siquiera hay NOPs, al menos durante los bits de datos,ya que el tiempo necesario para calcular el siguiente bit es justo 17 us, solo se usan NOPs al final de la transmision, porque ya no hay nada mas que calcular.
Ahora, si bien la rutina funciono a la primera prueba, haciendo que el sintetizador emitiera un HOLA, las siguientes ejecuciones no siempre andaban bien. Con la ayuda tecnica de the woz, se pudo solucionar esto, que era lo que sospechaba, por alguna razon el VIC o la interrupcion de la CIA no quedaban deshabilitados durante la transmision.
La conclusion es que ya pude dar el primer paso del plan, lo que sigue es integrar esta rutina con la interrupcion de 50/60 Hz, y luego escribir rutinas de manejo de un buffer de envio de secuencias al sintetizador. Cuando este implementado, el programador se limitaria a llamar a una rutina con un texto cargado, la rutina agregaria esta secuencia al buffer en RAM, y la rutina de interrupcion iria enviando como "tarea de fondo" estos bytes a un ritmo de 50 o 60 caracteres por segundo, segun el modelo de C64/128.
Todo esto permitiria que se pudieran hacer juegos en asm con soporte de voz, sin agregar un excesivo consumo de proceso.
Al final del camino va a haber un pequeño juego de demostracion, no va a ser gran cosa, solo una prueba con todo funcionando.
Me leí esta última explicación y de verdad me saco el sombre, y con el calor que hace lo dejo encima de la mesa, es muy bueno el laburo, y la explicacón clarita, a pesar que entiendo poco del tema.
Bueno, todo esto es trabajo obligado si quiero que el sintetizador se pueda usar en un juego. Tambien habria que hacer rutinas similares en MSX, TS2068, Spectrum y cualquier otra maquina que tenga alguna manera de conectarse al chip. Ahi no se si voy a poder escribir las rutinas necesarias, pero teniendo algo como referencia para C64, puede ser que alguno se anime a implementarlas en Z80. Probablemente, si no pierdo interes despues de terminar el codigo para C64, lo intente en otras maquinas con 6502, me interesan particularmente la C128 en modo 128, la Plus/4 y las Atari de 8 bits.
Para ir haciendo el codigo tuve que pensar primero como se va a usar, y eso implica ponerse a analizar como se implementa un juego, asi que la realizacion de estas rutinas en otras maquinas va a depender de que tan bien pueda conocer la arquitectura (hard y ROM) y la forma en que se hacen los juegos en esa maquina, en un tiempo razonable. El resultado final va a ser una especie de driver, y como dije un juego de ejemplo, con el codigo fuente disponible como parte del proyecto del sintetizador, junto con el archivo binario para grabarse el PIC, y el manual en una version actualizada.
Vamos a ver que sale, todavia falta.
Que buen laburo Jorge. Yo todabia no arme el de MSX , tengo ahi el integrado, me tengo que poner y hacerlo
Como conte en otro tema, ultimamente hice un nuevo sintetizador HR6 con el mismo chip que el HR4, y despues use algunas de esas optimizaciones tambien en el HR4, lo cual me dejo un poco de memoria libre para implementar alguna funcion extra. El problema es que no es demasiada memoria como para hacer algun cambio drastico, por lo que se me ocurrio que una funcion util podria ser que el sintetizador devuelva algunos parametros por el puerto serie, por ejemplo para saber cual es el tono o velocidad actual de la voz.
La comunicacion ida y vuelta en el sintetizador es algo que no tuvo prioridad en el desarrollo, cualquiera que lo use se daria cuenta que no hay manera de saber como esta configurada la voz, y la unica manera segura de obtener los resultados que uno espera es enviar comandos de inicializacion en el arranque del programa de usuario. Si por alguna razon uno no almacena esta informacion en un programa donde se cambia varias veces de voz, no queda otra que agregar los comandos correspondientes para asegurarse de que todo esta ajustado como uno quiere.
Sin embargo, desde el principio pense que en algun momento agregaria al menos un comando para consultar la version del sintetizador, pero esto interferia con mi decision de no agregar un buffer de transmision al programa, para simplificar el codigo. Mi decision fue que por cada byte que el PIC recibia, solo podia salir otro byte, y un comando para consultar la version requeriria enviar varios bytes como respuesta. Esto se podria llegar a solucionar enviando como respuesta un byte binario, pero desde el principio tambien tome la decision de trabajar solo con caracteres imprimibles, por lo que si quisiera que el PIC devolviera por ejemplo el numero 250, no tendria que devolver un byte con ese valor, sino 3 bytes, los codigos ASCII de '2', '5' y '0'. En este caso, por 1 byte recibido se devolverian 3, lo que requiere un buffer de transmision, y nos lleva al problema de que el usuario nos enviara este comando de consulta tantas veces que lleguemos a llenar el buffer de transmision por no poder responder a tiempo. Para evitar todos esos problemas, opte por responder un byte por cada byte recibido, y asi es como estan hechos todos los sintetizadores.
Pero dandole vueltas al asunto, vi que podia implementar comandos de consulta con solo 1 byte de respuesta. En los sintetizadores hay un jumper para seleccionar si se quiere recibir el eco de lo enviado al PIC, esta opcion es util si se conecta el sintetizador a una terminal serie, para ver en la terminal lo que uno tipea. Hacer un comando de consulta requeriria devolver el byte recibido (si esta activado el eco) y luego la respuesta, pero ahi estariamos en el mismo problema de que el usuario envie un monton de comandos de consulta seguidos, lo que llenaria el buffer de respuesta del PIC.
La solucion que elegi ahora es responder al comando en el propio eco del caracter enviado, por lo cual serian comandos muy especiales que no se comportarian como los otros: serian caracteres que no tienen eco, y los valores devueltos por el sintetizador serian binarios.
Una vez definido que eso se puede implementar en el PIC, faltaba verificar que era posible hacerlo en la C64 a 57600 bps, esto es, enviar un comando a 57600 bps, y recibir la respuesta a continuacion a esa velocidad.
Esto tiene complicaciones de todo tipo, un bit a 57600 bps dura 17 microsegundos, y en la C64 la instruccion mas rapida usa 2 microsegundos. Luego de enviado el byte a 57600 bps, que ya vimos que se puede hacer, hay que quedarse esperando el byte de respuesta, esto en la practica se hace esperando que la entrada RX se ponga en 0, a partir de lo cual comienza la serie de bits a leer. Si uno supiera cuanto tarda el sintetizador en responder desde que recibe el comando, en la C64 se podria hacer una recepcion a ciegas, es decir esperando cierta cantidad de tiempo, y comenzando a leer los bits uno por uno. Pero el tiempo de respuesta del sintetizador varia, y tambien varia el tiempo entre que se recibe el byte, y el programa del sintetizador se da cuenta de que hay un byte recibido. Se me ocurrio medir esto, y para eso capture tanto la entrada como la salida serie del PIC, dando como resultado que entre un byte recibido y la respuesta puede pasar tanto como 100 microsegundos, con bastante variacion, a veces 30, otras 60, 80, etc.
Ya que no podemos saber cuando el sintetizador va a responder, pero sabemos que lo maximo estaria alrededor de los 100 microsegundos, solo queda que el 6510 en la C64 este chequeando continuamente la entrada de datos una vez que termina de enviar el comando al PIC (tambien se podrian usar interrupciones, pero esto complicaria mas el programa).
Lo que quedaba era verificar si era posible recibir por soft a 57600 bps en la C64, y la respuesta para no alargar mas esto, es positiva. Luego de unas cuantas pruebas y fallas, logre enviar un byte a 57600 bps, recibir la respuesta desde el sintetizador, e imprimirla.
No estoy tan seguro de que la misma rutina funcione en PAL, porque los tiempos son muy criticos, y como no dispongo de C64 PAL, eso va a quedar para probarlo mas adelante. Por el momento estoy probando todo en la C128 NTSC.
Volviendo a todo lo anterior, ahora que esta probado que se puede hacer en la C64, puedo agregar esos comandos a la version 1.1 del sintetizador HR4, por lo que el problema vuelve a ser que comandos implementar. en principio los mas utiles serian la consulta de tono, nota y velocidad de la voz, cada una con su propio comando. Ya habra mas novedades cuando tenga un tiempo para hacer pruebas.