Reparando la ULA de un ZX-Interface 2

Sinclair QL, ZX81, +2, +3, 128K ...
Avatar de Usuario
wilco2009
MSX Turbo R
MSX Turbo R
Mensajes: 401
Registrado: 29 Ago 2013, 15:48
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: ZX81
consola_favorita: Sega Master System
Primera consola: Atari 2600
Gracias dadas: 1 vez
Gracias recibidas: 7 veces

Reparando la ULA de un ZX-Interface 2

Mensajepor wilco2009 » 23 May 2015, 13:41

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

Pinchar para ver video de demostración

Foto del invento funcionando:

Imagen

Y esta la caja cerrada con el conjunto dentro:

Imagen

La idea 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):

https://lh6.googleusercontent.com/-Ozpn ... %2Bsch.png

Estos los archivos Eagle.
https://drive.google.com/file/d/0B69T2l ... sp=sharing

Y el archivo JED este otro.
https://drive.google.com/file/d/0B69T2l ... sp=sharing

Aquí tenéis los fuentes en ABEL HDL.
https://drive.google.com/file/d/0B69T2l ... sp=sharing

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

Imagen

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:
[tab=30] - D0 = "Tecla 1" = LEFT1
[tab=30] - D1 = "Tecla 2" = RIGHT1
[tab=30] - D3 = "Tecla 3" = DOWN1
[tab=30] - D4 = "Tecla 4" = UP1
[tab=30] - 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:
[tab=30] - D0 = "Tecla 0" = FIRE2
[tab=30] - D1 = "Tecla 9" = UP2
[tab=30] - D3 = "Tecla 8" = DOWN2
[tab=30] - D4 = "Tecla 7" = RIGHT2
[tab=30] - 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.

Avatar de Usuario
mcleod_ideafix
Amiga 2500
Amiga 2500
Mensajes: 5316
Registrado: 06 Oct 2009, 04:12
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: Vectrex
Primera consola: TV Games/Pong Clone
Ubicación: Jerez de la Frontera
Gracias dadas: 12 veces
Gracias recibidas: 53 veces
Contactar:

Re: Reparando la ULA de un ZX-Interface 2

Mensajepor mcleod_ideafix » 23 May 2015, 23:38

Impresionante.... :)
Como te dije en la última Retro Madrid.... ya te falta menos para venirte al lado oscuro. Algún día la GAL no te será suficiente ;)

Para cuando eso pase, aquí tienes el código en Verilog de lo que iría dentro de la ULA de un IF2. En este caso te puedes ahorrar los diodos, aunque no los pullups en las entradas. El resultado te cabe en la CPLD más pequeñita que tiene Xilinx.

Código: Seleccionar todo

module ula_if2 (
  input wire a0,
  input wire a11,
  input wire a12,
  input wire iorq_n,
  input wire rd_n,
 
  input wire up1,
  input wire down1,
  input wire left1,
  input wire right1,
  input wire fire1,
 
  input wire up2,
  input wire down2,
  input wire left2,
  input wire right2,
  input wire fire2,
   
  output wire [4:0] d
  );
 
  wire puerto1_n = iorq_n | rd_n | a0 | a12;  // semifila 09876
  wire puerto2_n = iorq_n | rd_n | a0 | a11;  // semifila 12345
 
  assign d[0] = (~puerto1_n && ~fire1)? 1'b0 :
                (~puerto2_n && ~fire2)? 1'b0 :
                1'bz;

  assign d[1] = (~puerto1_n && ~up1)? 1'b0 :
                (~puerto2_n && ~up2)? 1'b0 :
                1'bz;

  assign d[2] = (~puerto1_n && ~down1)? 1'b0 :
                (~puerto2_n && ~down2)? 1'b0 :
                1'bz;
 
  assign d[3] = (~puerto1_n && ~right1)? 1'b0 :
                (~puerto2_n && ~right2)? 1'b0 :
                1'bz;

  assign d[4] = (~puerto1_n && ~left1)? 1'b0 :
                (~puerto2_n && ~left2)? 1'b0 :
                1'bz;
endmodule


Y lo bueno del asunto es, que sin cambiar de chip, y si te sientes "juguetón", puedes añadirle autodisparo seleccionable. Tan sólo tienes que traerte al chip las señales WR y INT del slot trasero. La cosa quedaría así:

Código: Seleccionar todo

module ula_if2 (
  input wire a0,
  input wire a11,
  input wire a12,
  input wire iorq_n,
  input wire rd_n,
  input wire wr_n,
  input wire int_n,
 
  input wire up1,
  input wire down1,
  input wire left1,
  input wire right1,
  input wire fire1,
 
  input wire up2,
  input wire down2,
  input wire left2,
  input wire right2,
  input wire fire2,
   
  inout wire [4:0] d
  );
 
  wire puerto1_n = iorq_n | rd_n | a0 | a12;  // semifila 09876
  wire puerto2_n = iorq_n | rd_n | a0 | a11;  // semifila 12345
 
  reg [3:0] divfreq = 4'b0000;
  always @(posedge int_n)
    divfreq <= divfreq + 1;
  wire rafaga_disparos = divfreq[3];

  reg [1:0] config_autodisparo = 2'b00; // latch para guardar configuración
  // Puerto I/O $E7FF
  wire write_config_n = iorq_n | wr_n | ~a0 | a11 | a12;
  wire read_config_n = iorq_n | rd_n | ~a0 | a11 | a12;

  always @* begin
    if (!write_config_n)
      config_autodisparo = d[1:0];
  end

  assign d[0] = (~puerto1_n && ~fire1 && ~config_autodisparo[0])? 1'b0 : // si no hay autodisparo...
                (~puerto1_n && ~fire1 &&  config_autodisparo[0])? rafaga_disparos : // si hay autodisparo...
                (~puerto2_n && ~fire2 && ~config_autodisparo[1])? 1'b0 :
                (~puerto2_n && ~fire2 &&  config_autodisparo[1])? rafaga_disparos :
                (~read_config_n)? config_autodisparo[0] :
                1'bz;

  assign d[1] = (~puerto1_n && ~up1)? 1'b0 :
                (~puerto2_n && ~up2)? 1'b0 :
                (~read_config_n)? config_autodisparo[1] :
                1'bz;

  assign d[2] = (~puerto1_n && ~down1)? 1'b0 :
                (~puerto2_n && ~down2)? 1'b0 :
                1'bz;
 
  assign d[3] = (~puerto1_n && ~right1)? 1'b0 :
                (~puerto2_n && ~right2)? 1'b0 :
                1'bz;

  assign d[4] = (~puerto1_n && ~left1)? 1'b0 :
                (~puerto2_n && ~left2)? 1'b0 :
                1'bz;
endmodule


Ahora, el puerto $E7FF (59391) sirve para leer y escribir la nueva configuración de autodisparo.
OUT 59391,0 : quita el autodisparo a los dos puertos
OUT 59391,1 : pone autodisparo en el puerto 1
OUT 59391,2 : pone autodisparo en el puerto 2
OUT 59391,3 : pone autodisparo en ambos puertos

El autodisparo es de unas 3 ráfagas por segundo. Debería ser suficiente para matar a todo bicho viviente en pantalla :P Se activa dejando pulsado el botón del joystick.
Recuerda: cada vez que se implementa un sistema clásico en FPGA, Dios mata a un purista

Avatar de Usuario
wilco2009
MSX Turbo R
MSX Turbo R
Mensajes: 401
Registrado: 29 Ago 2013, 15:48
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: ZX81
consola_favorita: Sega Master System
Primera consola: Atari 2600
Gracias dadas: 1 vez
Gracias recibidas: 7 veces

Re: Reparando la ULA de un ZX-Interface 2

Mensajepor wilco2009 » 24 May 2015, 00:40

Una maravilla las posibilidades del lado oscuro, jejejeje . Tengo que ponerme, pero siempre tengo algo que hacer antes. No se como lo hago. :(

Tengo el programador y la CPLD que me pasó Antonio, pero todavía no me he puesto a ello.

Además necesito ponerme con el tema de las CPLD para poder meter la placa definitiva del superupgrade+add-on en 10x10, y hacer una nueva versión del megaflash con ampliación de RAM y lowerROM.

Las placas del prototipo del megaflash+SX (con lowerROM pero sin RAM) llevan una GAL y ya me vienen de camino, pero para la ampliación de RAM me salen dos GAL más, con lo que para hacer la versión definitiva con todo tengo que hacerlo sí o sí con una CPLD.


Volver a “Sinclair/Spectrum”

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 37 invitados