ZXPP, clon de Spectrum en una Papilio Pro

Cursos, reparaciones, fichas, tutoriales, etc.

Moderador: Fundadores

Responder
Avatar de Usuario
Kyp !Sinclair 1
Hermano de Lucifer
Hermano de Lucifer
Mensajes: 3391
Registrado: 30 Sep 2013, 14:54
Ubicación: Madrid
Has thanked: 29 times
Been thanked: 157 times

ZXPP, clon de Spectrum en una Papilio Pro

Mensaje por Kyp »

¿Otro clon de Spectrum basado en una FPGA? Resulta que cuando empecé a oír hablar de las FPGAs supe que necesitaba una y tras investigar un poco me decidí por la Papilio Pro de Gadget Factory a la que añadí una Arcade Megawing. Tras un tiempo haciendo cosillas con esta placa probablemente no sea la mejor opción, pero eso es otra historia.

La placa de desarrollo:
http://papilio.gadgetfactory.net/index. ... PapilioPro
Imagen

La placa de conectores:
http://papilio.gadgetfactory.net/index. ... deMegaWing
Imagen

El caso es que creo que la gracia de todo esto es hacérselo uno mismo así que me he puesto manos a la obra y esto es lo que ha salido.
Avatar de Usuario
flopping
Fundador
Fundador
Mensajes: 9973
Registrado: 29 Mar 2013, 15:26
Ubicación: Valencia
Been thanked: 124 times
Contactar:

Re: ZXPP, clon de Spectrum en una Papilio Pro

Mensaje por flopping »

Acaba el post, que nos estas dejando con los dientes largo, jajajaajaja
No me hago responsable de mis post pues estan escritos bajo la influencia del alcohol y drogas psicotropicas, por la esquizofrenia paranoide.
(C) 1982-2024, 42 años de ZX Spectrum.
http://www.va-de-retro.com/ un foro "diferente".

Mi juego, que puedes descargar desde aqui
Avatar de Usuario
Kyp !Sinclair 1
Hermano de Lucifer
Hermano de Lucifer
Mensajes: 3391
Registrado: 30 Sep 2013, 14:54
Ubicación: Madrid
Has thanked: 29 times
Been thanked: 157 times

Re: ZXPP, clon de Spectrum en una Papilio Pro

Mensaje por Kyp »

Paciencia, que no es algo que se cuenta en un solo mensaje :D :D :D
Avatar de Usuario
Kyp !Sinclair 1
Hermano de Lucifer
Hermano de Lucifer
Mensajes: 3391
Registrado: 30 Sep 2013, 14:54
Ubicación: Madrid
Has thanked: 29 times
Been thanked: 157 times

Re: ZXPP, clon de Spectrum en una Papilio Pro

Mensaje por Kyp »

Paso 0: notas preliminares

La herramienta para crear los diseños que voy a usar es el "ISE Design Suite 14.7" la que facilita gratuitamente Xilinx, el fabricante de la FPGA. No es que sea el mejor IDE del mundo pero hace su trabajo (aunque es desesperadamente lento). Tampoco se le pueden poner muchas pegas porque, como digo, es gratuito. Existe otra Suite que supongo será mejor pero que es de pago (y bastante cara por cierto).

Voy a asumir que se tiene un cierto manejo del IDE, si alguien se atreve a meterse en el lío de seguir mis pasos aquí me tiene para resolver dudas.

Una nota importante, no pretendo hacer un clon 100% exacto del Spectrum. Me voy a tomar ciertas libertades, las más importantes son que tendrá salida VGA y que no tendrá contención (o mejor dicho arbitraje) de memoria.

Ahh, se me olvidaba. De los dos lenguajes más comunes que se usan para diseñar con FPGAs, VHDL y Verilog, voy a usar VHDL. Más que nada por que encontré antes un buen tutorial de este lenguaje. La verdad es que, si lo piensas, en el fondo son muy parecidos, simplemente se escriben las cosas de distinta forma.
Avatar de Usuario
antoniovillena
Demonio segundo orden
Demonio segundo orden
Mensajes: 1596
Registrado: 02 Abr 2013, 19:06
Been thanked: 1 time

Re: ZXPP, clon de Spectrum en una Papilio Pro

Mensaje por antoniovillena »

De momento puedes portar el código fuente de McLeod para el ZX-Uno, que hasta la fecha es la síntesis FPGA más fidedigna (y completa) que existe para ZX Spectrum. Todo el código está en el repositorio oficial:

http://www.atc.us.es/svn/zxuno/
Usuario: guest
Contraseña: zxuno

Por otro lado hay versiones más modernas de estas placas, en concreto la Papilio DUO-512Kb

http://www.seeedstudio.com/depot/Papili ... cPath=6_10

Con su placa de periféricos

http://www.seeedstudio.com/depot/Classi ... cPath=6_10
Avatar de Usuario
Kyp !Sinclair 1
Hermano de Lucifer
Hermano de Lucifer
Mensajes: 3391
Registrado: 30 Sep 2013, 14:54
Ubicación: Madrid
Has thanked: 29 times
Been thanked: 157 times

Re: ZXPP, clon de Spectrum en una Papilio Pro

Mensaje por Kyp »

antoniovillena escribió:De momento puedes portar el código fuente de McLeod para el ZX-Uno, que hasta la fecha es la síntesis FPGA más fidedigna (y completa) que existe para ZX Spectrum. Todo el código está en el repositorio oficial
Hay una diferencia insalvable, al menos por el momento, entre el ZX-Uno y la Papilio Pro y es la RAM. Vosotros, con muy buen criterio, usáis SRAM, pero mi placa lleva SDRAM. La diferencia es bastante notable. Mientras que con la SRAM el acceso es tan sencillo como meter una dirección en un bus y leerlo/escribirlo al cabo de un instante en el bus de datos, con la SDRAM hay que enviar comandos tales como decir cuantas palabras vas a leer, de que banco, mandar el comando de lectura, esperar un número variable de ciclos para que el dato esté disponible... entretanto mandar comandos de refresco... un lio vamos.

De momento he usado la BRAM de la FPGA. Tiene justo los 64K necesarios para el clon. Además se puede configurar como RAM de doble puerto, ideal para hacer la RAM baja (asi sí, sin contención, aunque ya he visto como hace McLeod para simularla e igual me animo).

De todas formas esto es un ejercicio mio para aprender a usar las FPGAs. Nada más. El ZX-Uno va mucho más allá y seguro que compro uno cuando esté listo. He dudado mucho en pedir un prototipo pero así me obligo a hacerlo yo mismo.

Por otra parte, el código de McLeod me ha venido muy bien como fuente de inspiración (o copia casi directa en algunos casos) :))

Por cierto que ya tengo un clon funcional a falta de que compre un conector DB9 para cargar de cinta. De momento he tirado de tus ROMs de juegos y al menos el Manic Miner funciona bien. Y las ROMs de test tampoco dan errores :D
antoniovillena escribió:Por otro lado hay versiones más modernas de estas placas, en concreto la Papilio DUO-512Kb
http://www.seeedstudio.com/depot/Papili ... cPath=6_10

Con su placa de periféricos
http://www.seeedstudio.com/depot/Classi ... cPath=6_10
Si, esta es mucho mejor, sobre todo porque tiene SRAM como el ZX-Uno y el microcontrolador te permitiría cargar los cores desde la SD muy fácilmente (como hace la Myst). Pero no existía cuando compre la Pro así me tengo que aguantar con lo que hay.
Avatar de Usuario
antoniovillena
Demonio segundo orden
Demonio segundo orden
Mensajes: 1596
Registrado: 02 Abr 2013, 19:06
Been thanked: 1 time

Re: ZXPP, clon de Spectrum en una Papilio Pro

Mensaje por antoniovillena »

Sí, lo de la SDRAM es un problema. El prototipo 0 del ZX-Uno fue una placa MOD-VGA. Dicha placa venía montada de serie con una SDRAM. Por suerte vendían una versión barata sin SDRAM y por la parte de atrás había una huella para SRAM, por lo que comprando esta y un chip de SRAM se podía hacer el apaño.

Si es por aprender, con la BRAM tienes lo justo para un 48K. El conector DB9 va casi directo a un pin de la FPGA, así que ten mucho cuidado con las tensiones que le metes. Lo ideal es hacerte un circuito de EAR basado en un transistor como tiene el ZX-Uno (mírate los esquemáticos).
Avatar de Usuario
Kyp !Sinclair 1
Hermano de Lucifer
Hermano de Lucifer
Mensajes: 3391
Registrado: 30 Sep 2013, 14:54
Ubicación: Madrid
Has thanked: 29 times
Been thanked: 157 times

Re: ZXPP, clon de Spectrum en una Papilio Pro

Mensaje por Kyp »

antoniovillena escribió:Sí, lo de la SDRAM es un problema. El prototipo 0 del ZX-Uno fue una placa MOD-VGA. Dicha placa venía montada de serie con una SDRAM. Por suerte vendían una versión barata sin SDRAM y por la parte de atrás había una huella para SRAM, por lo que comprando esta y un chip de SRAM se podía hacer el apaño.
Lo se, lo se. Sigo vuestros progresos desde le principio ;)

Estoy viendo la posibilidad de adaptar un controlador que hay para la SDRAM de forma que simule el uso de una SRAM. Como la SDRAM trabaja a una frecuencia mucho más rápida de lo que necesito (100 MHZ o más), se podría meter un módulo intermedio que exponga los pines de una SRAM, e internamente envié los comandos y almacene los datos que haga falta para manejar la SDRAM. Además eso me hace falta para poder clonar el DivMMC porque con la BRAM ya no tengo la ROM/RAM necesaria.
antoniovillena escribió:Si es por aprender, con la BRAM tienes lo justo para un 48K. El conector DB9 va casi directo a un pin de la FPGA, así que ten mucho cuidado con las tensiones que le metes. Lo ideal es hacerte un circuito de EAR basado en un transistor como tiene el ZX-Uno (mírate los esquemáticos).
Si, también me he 'inspirado' en el diseño del ZX-Uno para esto :D
Avatar de Usuario
Kyp !Sinclair 1
Hermano de Lucifer
Hermano de Lucifer
Mensajes: 3391
Registrado: 30 Sep 2013, 14:54
Ubicación: Madrid
Has thanked: 29 times
Been thanked: 157 times

Re: ZXPP, clon de Spectrum en una Papilio Pro

Mensaje por Kyp »

Paso 01, vídeo VGA

Este paso no es que sea estrictamente necesario, pero es lo primero que se suele hacer con una FPGA ya que es algo relativamente sencillo y, la verdad, es bastante estimulante ver que el dinero que te has gastado en la tarjeta hace algo más que encender y apagar unos cuantos LEDs.

Si buscáis en internet como debe ser una señal VGA verás un montón de información sobre diagramas de tiempos... duración de señales y sincronismos... y un montón de números para calcular cuanto debe durar cada señal.

En realidad es mucho más sencillo.

Una señal VGA estándar de 640x480 a 60Hz tiene la forma siguiente:
- Cada línea horizontal tiene 800 píxels. 640 son visibles y durante el resto se genera el sincronismo horizontal: |------640------|-HS-|
- Cada línea vertical tiene 525 píxels. 480 son visibles y durante el resto se genera el sincronismo vertical: |------480------|-VS-|
Los sincronismos no se generan durante todo el tiempo no visible, hay unos espacios antes y después llamados front y back porch que supongo eran necesarios para las TVs analógicas.

En esta página tenéis los parámetros para casi cualquier resolución VGA:
http://tinyvga.com/vga-timing

Necesitamos dos contadores, el horizontal cuenta de 0 a 799 y cada vez que pasamos por el 799 incrementamos el vertical que cuenta de 0 a 524.

Para generar los sincronismo simplemente mantenemos a 1 lógico la señal (es activa a nivel bajo) mientras no esté dentro de los rangos especificados, y la ponemos a 0 cuando corresponda. En este caso, del 656 al 751 para el horizontal y del 490 al 491 para el vertical.

Finalmente, mientras estemos en la zona visible ponemos un color (blanco) y a negro el resto del tiempo:

Código: Seleccionar todo

process(clock25)
begin
	if rising_edge(clock25) then
		if x < 799 then x <= x+1;
		else
			x <= (others => '0');
			if y < 524 then y <= y+1; 
			else
				y <= (others => '0');
			end if;
		end if;

		if x >= 640+16 and x < 640+16+96 then hs <= '0'; else hs <= '1'; end if;
		if y >= 480+10 and y < 480+10+ 2 then vs <= '0'; else vs <= '1'; end if;

		if x < 640 and y < 480 then
			rgb <= x"777";
		else
			rgb <= x"000";
		end if;
	end if;
end process;
Jugando con el valor asignado a la señal "rgb" durante el área visible se pueden hacer unos bonitos degradados.
No tiene los permisos requeridos para ver los archivos adjuntos a este mensaje.
Avatar de Usuario
Kyp !Sinclair 1
Hermano de Lucifer
Hermano de Lucifer
Mensajes: 3391
Registrado: 30 Sep 2013, 14:54
Ubicación: Madrid
Has thanked: 29 times
Been thanked: 157 times

Re: ZXPP, clon de Spectrum en una Papilio Pro

Mensaje por Kyp »

Paso 02, decodificando la pantalla

Ahora que ya sabemos como generar la señal de vídeo, para generar una imagen solamente necesitamos saber que información de color enviar por la salida RGB para cada píxel.

Como tenemos una pantalla de 640x480 píxels y el Spectrum tiene una resolución de 256x192 píxels voy a hacer lo siguiente para llenar la pantalla. Voy a aplicar un zoom de x2 a la imagen quedando en 512x384 píxels. El resto lo mostramos como borde lo que nos da 640-512=128, es decir, 64 píxels a derecha e izquierda y 480-384=96, es decir, 48 píxels por encima y por debajo. Hacer el zoom x2 es muy sencillo, simplemente hay que dividir entre 2 el contador horizontal y el vertical a la hora de calcular las posiciones de memoria que contienen la información para cada píxel.

La información de cada píxels está en dos posiciones de memoria, una indica si se ve el color de tinta o de papel y la otra los atributos (tinta, papel, brillo y flash). Como sólo podemos leer una posición de memoria cada vez, vamos a usar dos registros para guardar estos datos. Esto hay que hacerlo para cada 8 píxels (un byte).

Además, necesitamos obtener la información antes de que se vaya a pintar cada bloque de 8 píxelsy hay que conservarla mientras se pintan y a la vez leemos la información de los 8 siguientes. Por lo que necesitamos otros dos registros más.

Aquí lo complicado es tener el dato en el momento justo. En una FPGA las transferencias de datos son síncronas, esto es, todo pasa en los flancos de la señal de reloj. Por ejemplo, en un flaco positivo del reloj asignas la dirección a leer y al siguiente flanco obtienes el dato. Igualmente, los registros que guardan la información hacen la transferencia en un flanco de reloj.

Por último, como mientras se pinta un bloque de 8 píxels hay que cargar los datos de color de los 8 siguientes, uso un contador adelantado 16 pulsos de reloj (8x2 del zoom) que solo cuenta las coordenadas de pantalla, 0 a 511 (resolución horizontal) y 0 a 383 (resolución vertical). De esta forma, cuando voy a pintar por ejemplo el píxel (23,5) que contador vale (7, 5), o en el caso especial de los primeros 8 píxels (3, 0) valdría (499, 383).

El procedimiento queda de la siguiente forma, para cada 16 incrementos del contador horizontal hacemos lo siguiente (cuento de 0 a 15):
- 0: asignamos al bus de direcciones la dirección de memoria que contiene que 8 píxels están encendidos o apagados del próximo byte.
- 1: la memoria devuelve el dato.
- 2: traspasamos el dato al registro que guarda la información sobre los siguientes 8 píxels.
- 8: asignamos al bus de direcciones la dirección de memoria que contiene los atributos.
- 9: la memoria devuelve el dato.
-10: traspasamos el dato al registro que guarda la información sobre los atributos de los siguientes 8 píxels.
-15: traspasamos los datos de los dos registros a los otros dos que mantendrán la información de color de los 8 píxels que se van a pintar mientras se lee la de los 8 siguientes.
- En el resto de 'slots' no hacemos nada.

Una vez que tenemos la información de bitmap y atributos ya es cuestión de ver si el píxel que se va a pintar está encendido o apagado y en función de eso, si tiene o no flash o brillo, escoger un color de la paleta.

Código: Seleccionar todo

process(clock25)
	variable bpre : std_logic_vector(7 downto 0); -- precarga del bitmap
	variable apre : std_logic_vector(7 downto 0); -- precarga de atributos
	variable i, p : std_logic_vector(2 downto 0); -- i = INK, p = PAPER
	variable b, c : integer; -- b = nº de píxel (de los 8 de cada byte) que se va a pintar
	-- c = color resultante a pintar después de tener en cuenta si es INK o PAPER, el brillo y el flash
begin
	if rising_edge(clock25) then
		-- contadores de la señal VGA
		if x < 799 then x <= x+1;
		else
			x <= (others => '0');
			if y < 524 then y <= y+1; 
			else
				y <= (others => '0');
				f <= f+1; -- contador de flash
			end if;
		end if;

		-- señales de sincronismo
		if x >= 640+16 and x < 640+16+96 then hs <= '0'; else hs <= '1'; end if;
		if y >= 480+10 and y < 480+10+ 2 then vs <= '0'; else vs <= '1'; end if;

		-- zona visible
		if x >= 64 and x < 64+512 and y >= 48 and y < 48+384 then

			-- contador de coordenadas de pantalla adelantado 16 pulsos
			if x = 64+512-16 and y = 48+383 then xy <= (others => '0'); else xy <= xy+1; end if;

			-- proceso de captura de datos desde la memoria
			if xy(3 downto 0) = "0000" then va   <=       xy(17 downto 16)&xy(12 downto 10)&xy(15 downto 13)&xy(8 downto 4); end if;
			if xy(3 downto 0) = "1000" then va   <= "110"&xy(17 downto 13)&xy( 8 downto 4); end if;
			if xy(3 downto 0) = "0010" then bpre := vd; end if;
			if xy(3 downto 0) = "1010" then apre := vd; end if;
			if xy(3 downto 0) = "1110" then bmap <= bpre; attr <= apre; end if;

			-- calculamos en indice dentro de la paleta de colores
			-- valores de INK y PAPER
			b := 7-to_integer(unsigned(x(3 downto 1)));
			i := attr(2 downto 0);
			p := attr(5 downto 3);

			-- color del píxel en función de si está encendido o apagado y el flash
			if attr(7) = '1' then
				if f(5) = '1' then
					if bmap(b) = '0' then c := to_integer(unsigned(i)); else c := to_integer(unsigned(p)); end if;
				else
					if bmap(b) = '0' then c := to_integer(unsigned(p)); else c := to_integer(unsigned(i)); end if;
				end if;
			else
				if bmap(b) = '1' then c := to_integer(unsigned(i)); else c := to_integer(unsigned(p)); end if;
			end if;

			-- atributo de brillo
			if attr(6) = '1' then c := c+8; end if;

			-- color definitivo
			rgb <= palette(c);

		elsif x < 640 and y < 480 then
			-- zona del borde
			rgb <= x"700";
		else
			-- zona no visible
			rgb <= x"000";
		end if;
	end if;
end process;
No tiene los permisos requeridos para ver los archivos adjuntos a este mensaje.
Responder

Volver a “Cursos y Tutoriales”