viernes, 5 de junio de 2015

Reparando la ULA de un ZX-Interface 2

Hace algún tiempo que el amigo Fermars disponía de un IF2 con la ULA averiada, y comentándo en Va-De-Retro nos propusimos crear una ULA casera para poder sustituir este chip que es prácticamente imposible de conseguir hoy en día.

Dejamos el tema en espera durante algún tiempo, y el otro día retomamos el tema. Después de algunas pruebas a distancia, Fermars me envió el IF2 y este es el resultado.   :D



Y esta la caja cerrada con el conjunto dentro:


Lo primero que se necesita para poder abordar el tema es el esquema del interface:




Como se puede ver en el esquema anterior, el circuito es muy simple. Consta de una ULA que controla la gestión de los joysticks y el simple cableado para enrutar el slot de los cartuchos y la expansión del bus para la conexión de una zx-printer.

La gestión del joystick consiste en leer el estado de pulsación de los botones y direcciones del joystick y convertirlos en pulsaciones de teclas. Como decía antes, de esto se encarga la ULA, no interviniendo ningún otro circuito en el tema, por lo que utilizando una GAL, quizás podamos emular su funcionalidad..
La idea inicial era utilizar una GAL20v8 para sustituir a la ULA, pero al final me han hecho falta también algunas resistencias y diodos.

El esquema final es este (abrir en una pestaña nueva para ver en detalle):


Estos los archivos Eagle: Descargar

Y el archivo JED este otro: Descargar

Aquí tenéis los fuentes en ABEL HDL: Descargar

Lo primero que hice fue probar en una placa de entrenamiento casera.



Y después de algunos cambios las pruebas fueron satisfactorias.
La idea inicial era utilizar solo la GAL sin ningún componente adicional, pero enseguida me encontré con algunas dificultades.

La primera de ellas fue que la distribución lógica de la GAL no permitía dejar cada una de las salidas por separado en estado de alta impedancia sin consumir una patilla adicional. Esto era necesario, para no bloquear las semifilas superiores del teclado.
El tema es que hay que forzar solo los bits que son cero del bus de datos, que correponden con una tecla pulsada, ya que si forzamos los unos el teclado no podrá poner ceros en el bus y no nos funcionarán las dos semifilas superiores.

Este hecho me obligó a añadir diodos para dejar pasar únicamente los ceros. El resultado debería ser un OR entre las pulsaciones del bus y el teclado.

Otra conclusión es que no te puedes fiar de las resistencias internas de pull-up, porque si dejas desconectada una patilla se comporta como si fuera un registro, es decir conserva su último estado. Pienso que esto debe ser configurable por algún sitio pero no he encontrado la opción. Son por tanto necesarias las resistencias de pull-up de entrada correspondientes a las direcciones de los dos joystick.

Voy a exponer el comportamiento teórico que debe tener:

- Para que se habiliten las salidas debemos tener 0v en las siguientes señales: /RD, /IORQ, A0 y al menos una entre A11 y A12.

- La semifila de la izquierda "12345" es el primer joystick y utiliza el puerto $F7FE (1111 0111 1111 1110). Se identifica con la decodificación parcial A11=0 y A0=0. Se corresponden las siguientes teclas y botones de joystick:

- D0  = "Tecla 1" = LEFT1
- D1  = "Tecla 2" = RIGHT1
- D3  = "Tecla 3" = DOWN1
- D4  = "Tecla 4" = UP1
- D5  = "Tecla 5" = FIRE1

- La semifila de la derecha "67890" es el segundo joystick y utiliza el puerto $EFFE (1110 1111 1111 1110). Se identifica con la decodificación parcial A12=0 y A0=0. Se corresponden las siguientes teclas y botones de joystick:
- D0  = "Tecla 0" = FIRE2
- D1  = "Tecla 9" = UP2
- D3  = "Tecla 8" = DOWN2
- D4  = "Tecla 7" = RIGHT2
- D5  = "Tecla 6" = LEFT2

Si tenemos las resistencias colocadas en las entradas entre +5v y cada patilla, las entradas se mantienen a +5v en estado de reposo. Estos +5v son débiles gracias a la resistencia que hemos intercalado, por lo que cualquier pulsación de una de las direcciones o del botón de fuego conecta el pin con masa y lo lleva a 0v.
Mientras el ordenador no está consultando el teclado, la GAL mantiene en alta impedancia las salidas ya que no se cumple /RD=/IORQ=A0=0. En el momento en el que consulta, por ejemplo, la semifila izquierda /RD=/IORQ=A0=A11=0, momento en el cual las salidas copian el estado de las entradas, es decir, si teníamos pulsado LEFT1, tendremos su patilla a 0V y D0 tendrá 0V mientras que el resto de las entradas estarán a +5v gracias a las resistencias de pull-up, y por tanto las salidas D1,D2,D2 y D4 tendrán 5v (o algo parecido mayor que 2,5V).

Para la otra semifila será lo mismo pero se deberá cumplir /RD=/IORQ=A0=A12=0.

Al final, la lógica de la GAL se resume en lo siguiente:

DATAOE = (A0
     # IORQ
     # RD
     # A11 & A12);
D4 = (!RD & !IORQ & !A0 & A11 & !A12 & LEFT2
     # !RD & !IORQ & !A0 & !A11 & FIRE1);
D4.OE = (!DATAOE);
D3 = (!RD & !IORQ & !A0 & A11 & !A12 & RIGHT2
     # !RD & !IORQ & !A0 & !A11 & UP1);
D3.OE = (!DATAOE);
D2 = (!RD & !IORQ & !A0 & A11 & !A12 & DOWN2
     # !RD & !IORQ & !A0 & !A11 & DOWN1);
D2.OE = (!DATAOE);
D1 = (!RD & !IORQ & !A0 & A11 & !A12 & UP2
     # !RD & !IORQ & !A0 & !A11 & RIGHT1);
D1.OE = (!DATAOE);
D0 = (!RD & !IORQ & !A0 & A11 & !A12 & FIRE2
     # !RD & !IORQ & !A0 & !A11 & LEFT1);
D0.OE = (!DATAOE);
Lo anterior, en un lenguaje de descripción un poco más inteligible quedaría como sigue:
!DATAOE = !(RD#IORQ) & (!A0&!A11 # !A0&!A12);
Data.oe = !DATAOE;
when !(RD # IORQ) then {
"Sinclair Left
when !A11 & !A0 then {
Data = [FIRE1,UP1,DOWN1,RIGHT1,LEFT1];
}
"Sinclair Right
else when !A12 & !A0 then {
Data = [LEFT2,RIGHT2,DOWN2,UP2,FIRE2];
}
}

Como veis, la solución es bastante sencilla, pero no por ello menos interesante.

Espero que hayáis disfrutado con esta entrega, yo la verdad es que he aprendido bastante, y sobre todo he disfrutado con el desarrollo.

Ahora, por fin mi amigo Fermars puede volver a disfrutar de su Interface 2. 
Con lo anterior ya me doy por satisfecho, pero me encantaría saber que la publicación de estas líneas pueda ayudar a devolver a la vida a algún Interface 2 más que ya se había dado por muerto.

Un saludo y hasta la próxima.

Alejandro Valero (wilco2009)