Videojuego FPGA en VHDL

27
Videojuego FPGA en VHDL Realizaremos paso a paso un sencillo ejemplo de entretenimiento para aprender a programar nuestra FPGA, para ello usaremos la tarjeta de Xilinxs, Spartan III Starter Kit. Objetivo Se trata de implementar un sencillo videojuego que ponga a prueba los reflejos del jugador. El objetivo del juego se trata de atrapar a los escurridizos bits que irán apareciendo de forma aleatoria en los LED (LD0, LD1, LD2). Para ello habrá que accionar los pulsadores (BTN0, BTN1, BTN2) mientras los LED correspondientes estén todavía encendidos. La partida se iniciará tras pulsar el Reset del sistema (BTN3) y durará 30 segundos. Los led permanecerán quietos durante 0.25 segundos antes de pasar a su siguiente configuración. El visualizador de cuatro dígitos mostrará en todo momento el número de bits atrapados desde el comienzo de la partida.No será válido dejar los pulsadores permanentemente actuados (emplear monoestable no redisparable en estas entradas, por ejemplo, versiones basadas en el circuito antirrebote que se menciona en las sugerencias). Para generar la secuencia pseudoaleatoría se empleará un LFSR (Linear FeedBack Shift Register). Los circuitos LFSR se utilizan en infinidad de sistemas electronicos para generar secuencias pseudoaleatorias con un periodo garantizado arbitrariamente largo, de forma simple y eficiente. Consiste en un registro de desplazamiento formado por una serie de biestables conectados en serie con realimentación XOR de sus salidas. A continuación puede verse un ejemplo de un LFSR de 5 bits. La elección de las salidas reañimentadas es fundamental para conseguir una máxima longitud de la secuencia sin repeticiones. Para este trabajo emplearemos un LFSR de 31 bits realimentando las salidas 2 y 30 (numerandolas desde cero), lo que generará secuencias sin

Transcript of Videojuego FPGA en VHDL

Page 1: Videojuego FPGA en VHDL

Videojuego FPGA en VHDL

Realizaremos paso a paso un sencillo ejemplo de entretenimiento para aprender a programar nuestra FPGA, para ello usaremos la tarjeta de Xilinxs, Spartan III Starter Kit.

Objetivo

Se trata de implementar un sencillo videojuego que ponga a prueba los reflejos del jugador. El objetivo del juego se trata de atrapar a los escurridizos bits que irán apareciendo de forma aleatoria en los LED (LD0, LD1, LD2). Para ello habrá que accionar los pulsadores (BTN0, BTN1, BTN2) mientras los LED correspondientes estén todavía encendidos. La partida se iniciará tras pulsar el Reset del sistema (BTN3) y durará 30 segundos. Los led permanecerán quietos durante 0.25 segundos antes de pasar a su siguiente configuración.

El visualizador de cuatro dígitos mostrará en todo momento el número de bits atrapados desde el comienzo de la partida.No será válido dejar los pulsadores permanentemente actuados (emplear monoestable no redisparable en estas entradas, por ejemplo, versiones basadas en el circuito antirrebote que se menciona en las sugerencias).

Para generar la secuencia pseudoaleatoría se empleará un LFSR (Linear FeedBack Shift Register). Los circuitos LFSR se utilizan en infinidad de sistemas electronicos para generar secuencias pseudoaleatorias con un periodo garantizado arbitrariamente largo, de forma simple y eficiente. Consiste en un registro de desplazamiento formado por una serie de biestables conectados en serie con realimentación XOR de sus salidas. A continuación puede verse un ejemplo de un LFSR de 5 bits.

La elección de las salidas reañimentadas es fundamental para conseguir una máxima longitud de la secuencia sin repeticiones. Para este trabajo emplearemos un LFSR de 31 bits realimentando las salidas 2 y 30 (numerandolas desde cero), lo que generará secuencias sin repeticiones de aproximadamente 2.200 millones de números. Utilizaremos las tres de menor peso como patrón para encender los led.

Una característica de los LFSR es que quedan bloqueados si su contenido es cero. Por ello es necesario inicializarlos con una semilla (un valor distinto de cero).

Mejoras realizadas:

Inclusión de varios niveles de dificultad, aumentando y disminiyundo el tiempo que los leds permanecen quietos. Esta seleccion se ha realizado mediante los interruptores delizantes.

Page 2: Videojuego FPGA en VHDL

Incluir varios niveles de dificultad aumentando o disminuyendo el número de leds que pueden encenderse a la vez. Para ello emplearemos una tabla de búsqueda o lookup de ocho elementos que contendrían los led a encender. La selección se realizará mediante los interruptores deslizantes.

Métodos empleados:

Usar contadores BCD con acarreo y permiso para almacenar la puntuación. El contador sólo contará en los flancos de subida de se señal de reloj cuando el permiso esté a 1. El acarreo valdrá 1 mientras el contador se halle en su valor máximo y 0 para el resto de valores posibles. El accareo de cada contador será el permiso del siguiente.

Emplear un único decodificador de 7 segmentos y la técnica de multiplexación (ver manual) para controlar los cuatro dígitos de la placa para encender un número.

Usar un prescaler o divisor que genere a partir de los 50MHz disponibles en la placa las frecuencias necesarias para la aplicación.

Incluir circuitos antirrebote en las entradas conectadas a pulsadores (ver "lenguaje Templates"->"VHDL"->"Synthesis Templates"->"Debounce circuit" en la herramienta Xilinx ISE).

Manual de usuario

Primeramente vamos a explicar el procedimiento lineal que sigue el sistema para realizar el videojuego.

El juego no comienza hasta que pulsemos el botón 3, lo que quiere decir que el sistema está siempre esperando a que se pulse dicho botón.

Antes de pulsar el botón 3 deberemos seleccionar el tiempo de juego de cada partida así como la dificultad del juego, ya sea con la velocidad en que aparecen los leds o si pueden aparecer 1 o varios leds a la vez, estas opciones de juego las seleccionaremos con los deslizadores de la tarjeta, tal y como aparece a continuación:

Duración de juego:

SW1 SW010 SEG 0 030 SEG 0 140 SEG 1 060 SEG 1 1

Velocidad de los leds:

SW3 SW21 HZ 0 02 HZ 0 14 HZ 1 08 HZ 1 1

Número de leds:

SW4UN LED 1

VARIOS LED 0

Page 3: Videojuego FPGA en VHDL

Hay que tener en cuenta que 0 será el deslizador hacia abajo y 1 será hacia arriba.

Se sugiere que para una mayor comprensión y seguimiento del proyecto puede bajarse el archivo "disposición ordenada de bloques y señales", el cual se puede encontrar en el punto Download de este mismo link. Es recomendable a la hora de hacer una aplicación en una FPGA se siga un orden establecido en bloques y señales que se haya hecho previamente sobre papel, ya que este paso nos hará ahorrar tiempo a la hora de pasarlo a código.

Funcionamiento

Una vez seleccionado las opciones de nuestro juego pulsaremos el botón 3, dicho botón será el encargado de iniciar o activar el componente Selector tiempo de Juego, el cual mantendrá un pulso a  nivel alto el tiempo que hayamos seleccionado en el juego mediante los deslizadores SW0 y SW1, cuando acabe el tiempo de juego volverá a poner a nivel bajo el pulso con la consecuencia de la finalización del juego.

Este pulso será a su vez el que active el componente Selector de Frecuencia, esté será el encargado se sacar un tren de pulsos a la frecuencia que hemos seleccionado previamente mediante los deslizadores SW2 y SW3, el cual actúa como habilitación a los monoestables, tanto el monoestable de la salida aleatoria como el monoestable de los pulsadores.

El componente Monoestable Salida Aleatoria recibe la habilitación del tren de pulsos del selector de frecuencia y la salida de la semilla producida por el componente Salida Aleatoria el cual actúa como “simulador” de alguien que pulsa otros pulsadores distintos a los nuestros, ya que nosotros pulsamos unos botones (BTN0, BTN1, BTN2) cuya señal llega al componente Monoestable y es activado por el tren de pulsos del selector de frecuencia.

 Por lo tanto ya tenemos dos pulsaciones, una producida por la máquina (LEDs) y otra producida por nosotros mismos, lo que hacemos es comparar dichas pulsaciones para ver si han sido iguales mediante el componente Comparador.

La semilla generada es aleatoria con lo que hay si queremos que se encienda sólo un led hay que codificar la señal de la semilla mediante el componente Codificador.

Aquí por tanto tenemos dos procesos en paralelo.

1.- Comparador:

Este comparará lo pulsado por el jugador con el resultado de la salida aleatoria y dará un pulso alto si la comparación es correcta.

2.- Codificador + comparador:

La salida aleatoria la pasamos por el codificador con lo que sólo se encenderá un led. La salida del codificador irá a parar a la entrada del comparador como si fuese la nueva salida aleatoria pero que en este caso es sólo un led, para luego comparar la nueva salida aleatoria con lo pulsado por el jugador y dar un pulso alto si la comparación es correcta.

Tenemos un proceso en paralelo, ¿entonces como sabemos que salida nos interesa y que comparador nos interesa?, es aquí donde entra en juego el deslizador SW4 y el componente Multiplexor Encender Leds, dicho multiplexor tiene como entrada controladora el SW4 y como entradas las entradas y salidas

Page 4: Videojuego FPGA en VHDL

del codificador y la comparación, si el SW4 es cero seleccionaremos el proceso paralelo del comparador y si SW4 es uno, entonces seleccionaremos el proceso paralelo del codificador + comparador. Las salidas del multiplexor encienden o apagan los led de la FPGA así como también tiene una salida que dará un pulso alto si la comparación ha sido correcta.

Disponemos un componente llamado Contador de Aciertos el cual cuenta los pulsos que nos llega del multiplexor encender leds, los cuales son los aciertos que el jugador a realizado.

Dicha suma se saca por los display gracias a los componentes Multiplexor de Display yConmutador de display, el conmutador enciende de forma continuada sólo un determinado display habilitándolo durante un periodo de tiempo y dándole el valor correspondiente de la suma de aciertos.

Manual avanzado

Vamos a ver más internamente el proceso viendo el código de cada componente.

1.- SELECTOR TIEMPO DE JUEGO:

Este componente es el encargado de decir el tiempo del juego, para ello está distribuido en otras 5 entidades, de las cuales 4 son para cada tiempo de juego (10 seg, 30 seg, 40 seg y 60 seg) o la quinta es un multiplexor de selección de dichos tiempos.

Estos tiempos se realizan mediante un contador de pulsos de reloj de la placa que son 50Mhz que son 20 ns, si queremos un tiempo de 10 segundos (10.000.000.000 ns), entonces no es más que hacer el siguiente cociente:

10.000.000.000 / 20 = 500.000.000 cuentas

1.1 Selector tiempo de juego:

Entidad que contiene los cinco componentes ya citados anteriormente.

entity selectorTiempoDeJuego is Port ( CLK : in std_logic;           rst : in std_logic;                                                 seleccion:IN STD_LOGIC_VECTOR(1 DOWNTO 0);           output_tiempo_juego : out std_logic);end selectorTiempoDeJuego;

architecture STRUCTURAL of selectorTiempoDeJuego is

component contador10seg isPort ( CLK : in std_logic;           rst : in std_logic;           output_10seg : out std_logic);end component;

component contador30seg isPort ( CLK : in std_logic;           rst : in std_logic;           output_30seg : out std_logic);end component;

Page 5: Videojuego FPGA en VHDL

component contador40seg is Port ( CLK : in std_logic;           rst : in std_logic;           output_40seg : out std_logic);end component;

component contador60seg is    Port ( CLK : in std_logic;           rst : in std_logic;           output_60seg : out std_logic);end component;

component muxSelectorTiempoDeJuego isPort ( input_10seg : in std_logic;           input_30seg : in std_logic;           input_40seg : in std_logic;           input_60seg : in std_logic;                      seleccion : in std_logic_vector(1 downto 0);           salida_tiempo_juego : out std_logic);end component;

 SIGNAL SAL10S:std_logic; SIGNAL SAL30S:std_logic; SIGNAL SAL40S:std_logic; SIGNAL SAL1M:std_logic; SIGNAL SAL_MUX:std_logic;begin

TIEMPO_10S:contador10seg PORT MAP(                                                                              CLK=>CLK,                                                                              output_10seg=>SAL10S,                                                                              rst=>rst);

TIEMPO_30S:contador30seg PORT MAP(                                                                              CLK=>CLK,                                                                              output_30seg=>SAL30S,                                                                              rst=>rst);

TIEMPO_40S:contador40seg PORT MAP(                                                                              CLK=>CLK,                                                                              output_40seg=>SAL40S,                                                                              rst=>rst);

TIEMPO_1M:contador60seg PORT MAP(                                                                              CLK=>CLK,                                                                              output_60seg=>SAL1M,                                                                              rst=>rst);

 SELECTOR:muxSelectorTiempoDeJuego PORT MAP(                                                                              seleccion=>seleccion,                                                                              input_10seg=>SAL10S,                                                                              input_30seg=>SAL30S,                                                                              input_40seg=>SAL40S,                                                                              input_60seg=>SAL1M,                                                                              salida_tiempo_juego=>SAL_MUX);

Page 6: Videojuego FPGA en VHDL

 output_tiempo_juego<= SAL_MUX;end Structural;

1.2 Contador 10 segundos:

Contador es un acumulador de ciclos de reloj que pone a uno una salida el tiempo de dicho contador.

entity contador10seg isPort ( CLK : in std_logic;           rst : in std_logic;           output_10seg : out std_logic);end contador10seg;

architecture Behavioral of contador10seg is                SIGNAL SALIDA_TIEMPO_COPY: STD_LOGIC:='0';                SIGNAL ACU1:INTEGER RANGE 0 TO 500000000:=0;beginoutput_10seg<=SALIDA_TIEMPO_COPY ;  PROCESS(CLK,rst,salida_tiempo_copy,ACU1)  BEGIN

 IF rst'EVENT AND rst='0'THEN     SALIDA_TIEMPO_COPY<='1';  END IF;  IF CLK'EVENT AND CLK='1' AND SALIDA_TIEMPO_COPY='1'THEN        ACU1<=ACU1+1;                END IF;    IF ACU1=500000000 AND SALIDA_TIEMPO_COPY='1' THEN SALIDA_TIEMPO_COPY<='0';  END IF;                                                                              IF ACU1=500000000  THEN ACU1<=0;  END IF;                  END PROCESS ;end Behavioral;

1.3 Contador 30 segundos:

Contador es un acumulador de ciclos de reloj que pone a uno una salida el tiempo de dicho contador.

entity contador30seg isPort ( CLK : in std_logic;           rst : in std_logic;           output_30seg : out std_logic);end contador30seg;

architecture Behavioral of contador30seg isSIGNAL SALIDA_TIEMPO_COPY: STD_LOGIC;                SIGNAL ACU2:INTEGER RANGE 0 TO 1500000000:=0;beginoutput_30seg<=SALIDA_TIEMPO_COPY ;  PROCESS(CLK,rst,SALIDA_TIEMPO_COPY,ACU2)  BEGIN

 IF rst'EVENT AND rst='0'THEN     SALIDA_TIEMPO_COPY<='1';  END IF;

Page 7: Videojuego FPGA en VHDL

  IF CLK'EVENT AND CLK='1' AND SALIDA_TIEMPO_COPY='1'THEN        ACU2<=ACU2+1;                END IF;  IF ACU2=1500000000 AND SALIDA_TIEMPO_COPY='1' THEN SALIDA_TIEMPO_COPY<='0';  END IF;                  IF ACU2=1500000000  THEN ACU2<=0;  END IF;                  END PROCESS ;

end Behavioral;

1.4 Contador 40 segundos:

Contador es un acumulador de ciclos de reloj que pone a uno una salida el tiempo de dicho contador.

entity contador40seg is Port ( CLK : in std_logic;           rst : in std_logic;           output_40seg : out std_logic);end contador40seg;

architecture Behavioral of contador40seg isSIGNAL SALIDA_TIEMPO_COPY: STD_LOGIC;                SIGNAL ACU3:INTEGER RANGE 0 TO 2000000000:=0;

beginoutput_40seg<=SALIDA_TIEMPO_COPY ;  PROCESS(CLK,rst,SALIDA_TIEMPO_COPY,ACU3)  BEGIN

 IF rst'EVENT AND rst='0'THEN     SALIDA_TIEMPO_COPY<='1';  END IF;  IF CLK'EVENT AND CLK='1' AND SALIDA_TIEMPO_COPY='1'THEN        ACU3<=ACU3+1;                END IF;  IF ACU3=2000000000 AND SALIDA_TIEMPO_COPY='1' THEN SALIDA_TIEMPO_COPY<='0';  END IF;                  IF ACU3=2000000000  THEN ACU3<=0;  END IF;                  END PROCESS ;

end Behavioral;

1.5 Contador 60 segundos:

Contador es un acumulador de ciclos de reloj que pone a uno una salida el tiempo de dicho contador.

entity contador60seg is    Port ( CLK : in std_logic;           rst : in std_logic;           output_60seg : out std_logic);end contador60seg;

architecture Behavioral of contador60seg isSIGNAL SALIDA_TIEMPO_COPY: STD_LOGIC;

Page 8: Videojuego FPGA en VHDL

SIGNAL ACU4:INTEGER RANGE 0 TO 1500000000:=0;SIGNAL ACU5:INTEGER RANGE 0 TO 10:=0;--SIGNAL ACU5:REAL RANGE 0 TO 10:=0;beginoutput_60seg<=SALIDA_TIEMPO_COPY ;  PROCESS(CLK,rst,SALIDA_TIEMPO_COPY,ACU4,ACU5)  BEGIN

 IF rst'EVENT AND rst='0'THEN     SALIDA_TIEMPO_COPY<='1';  END IF;  IF CLK'EVENT AND CLK='1' AND SALIDA_TIEMPO_COPY='1'THEN        ACU4<=ACU4+1;                END IF;  IF ACU4=1500000000 AND SALIDA_TIEMPO_COPY='1' THEN                 ACU5<=ACU5+1;  END IF;                  IF ACU4=1500000000 AND ACU5=2 AND SALIDA_TIEMPO_COPY='1' THEN                SALIDA_TIEMPO_COPY<='0';                END IF;                IF ACU4=1500000000 AND ACU5=2 AND SALIDA_TIEMPO_COPY='0' THEN                ACU5<=0;                END IF;                IF ACU4=1500000000 AND ACU5=0 AND SALIDA_TIEMPO_COPY='0' THEN                ACU5<=0;                END IF;                  END PROCESS ;

end Behavioral;

1.6 Multiplexor selector de tiempo:

Selector del contador que vamos a aplacar a nuestro juego, para ello las entradas de selección son los deslizadores cero y uno.

entity muxSelectorTiempoDeJuego isPort (        input_10seg : in std_logic;           input_30seg : in std_logic;           input_40seg : in std_logic;           input_60seg : in std_logic;                      seleccion : in std_logic_vector(1 downto 0);           salida_tiempo_juego : out std_logic);end muxSelectorTiempoDeJuego;

architecture Behavioral of muxSelectorTiempoDeJuego isSIGNAL O_COPY: STD_LOGIC;beginsalida_tiempo_juego<=O_COPY; PROCESS            (input_10seg,input_30seg,input_40seg,input_60seg,seleccion) BEGIN                  IF seleccion="00" THEN  O_COPY<=input_10seg;                 END IF;                 IF seleccion="01" THEN  O_COPY<=input_30seg;                 END IF;                 IF seleccion="10" THEN  O_COPY<=input_40seg;                 END IF;

Page 9: Videojuego FPGA en VHDL

                 IF seleccion="11" THEN  O_COPY<=input_60seg;                                 END IF;END PROCESS;

end Behavioral;

2.- SELECTOR FRECUENCIAS LEDS:

Es la entidad encargada de sacar un tren de pulsos a una frecuencia determinada por el usuario mediante los deslizadores dos y tres.

2.1 Selector de frecuencias leds:

Entidad compuesta por un multiplexor cuyas entradas de selección  son los deslizadores dos y tres y otra entidad denominada preescaler encargada de dividir la señal del reloj en un tren de pulsos a la frecuencia seleccionada por el usuario.

Entity SelectorFrecuenciaLeds is    Port ( CLK : in std_logic;           ENABLE : in std_logic;           output_frecuencia_leds : out std_logic;           seleccion : in std_logic_vector(1 downto 0));end SelectorFrecuenciaLeds;

architecture STRUCTURAL  of SelectorFrecuenciaLeds iscomponent muxSelectorFrecuenciaLeds isPort ( input_1hz : in std_logic;           input_2hz : in std_logic;           input_4hz : in std_logic;           input_8hz : in std_logic;           enable : in std_logic;           seleccion : in std_logic_vector(1 downto 0);           salida_frecuencia_leds : out std_logic);end component;

component preescaler isPort ( input_50MHz : in std_logic;                                                 output_8Hz : OUT std_logic;                                                 output_4Hz : OUT std_logic ;                                                 output_2Hz : OUT std_logic;           output_1Hz : OUT std_logic);end component;

SIGNAL SAL8:std_logic; SIGNAL SAL4:std_logic; SIGNAL SAL2:std_logic; SIGNAL SAL1:std_logic; SIGNAL SAL_MUX:std_logic;

begin

SELECTOR:muxSelectorFrecuenciaLeds PORT MAP(

Page 10: Videojuego FPGA en VHDL

                                                                              seleccion=>seleccion,                                                                              enable=>ENABLE,                                                                              input_1hz=>SAL1,                                                                              input_2hz=>SAL2,                                                                              input_4hz=>SAL4,                                                                              input_8hz=>SAL8,                                                                              salida_frecuencia_leds=>SAL_MUX                                                               );GENERATOR:preescaler PORT MAP(                                                                              input_50MHz=>CLK,                                                                              output_1HZ=>SAL1,                                                                              output_2HZ=>SAL2,                                                                              output_4HZ=>SAL4,                                                                              output_8HZ=>SAL8);

                output_frecuencia_leds<= SAL_MUX;

end Structural;

2.2 Multiplexor selector de frecuencias leds:

Selección de frecuencia de los dependiendo de los deslizadores, cuyas entradas del multiplexor son las salidas de las diferentes frecuencias del preescaler.

entity muxSelectorFrecuenciaLeds isPort ( input_1hz : in std_logic;           input_2hz : in std_logic;           input_4hz : in std_logic;           input_8hz : in std_logic;           enable : in std_logic;           seleccion : in std_logic_vector(1 downto 0);           salida_frecuencia_leds : out std_logic);end muxSelectorFrecuenciaLeds;

architecture Behavioral of muxSelectorFrecuenciaLeds isSIGNAL O_COPY: STD_LOGIC;beginsalida_frecuencia_leds<=O_COPY; PROCESS            (input_1hz,input_2hz,input_4hz,input_8hz,enable,seleccion) BEGIN IF enable='0' THEN                  O_COPY<='0';                                END IF;                 IF seleccion="00" AND enable='1' THEN    O_COPY<=input_1hz;                                END IF;                  IF seleccion="01" AND enable='1' THEN    O_COPY<=input_2hz;                                END IF;                 IF seleccion="10" AND enable='1' THEN    O_COPY<=input_4hz;                                END IF;                 IF seleccion="11" AND enable='1' THEN    O_COPY<=input_8hz;                                 END IF; END PROCESS;

end Behavioral;

2.3 Prescaler:

Page 11: Videojuego FPGA en VHDL

Entidad constituida por un divisor de ocho hercios y divisores de frecuencia a la mitad.

entity preescaler isPort ( input_50MHz : in std_logic;                                                 output_8Hz : OUT std_logic;                                                 output_4Hz : OUT std_logic ;                                                 output_2Hz : OUT std_logic;           output_1Hz : OUT std_logic);end preescaler;

architecture Structural of preescaler iscomponent divisor8Hz isPort ( CLK : in std_logic;           output_8hz : out std_logic);end component;

component divisorFrecuenciaMitad is    Port ( CLK : in std_logic;           SALIDA : out std_logic);end component;

 SIGNAL SAL8HZ:std_logic; SIGNAL SAL4HZ:std_logic; SIGNAL SAL2HZ:std_logic; SIGNAL SAL1HZ:std_logic;

begin

PRIMER_DIVISOR:divisor8Hz PORT MAP(                                                                              CLK=>input_50MHz,                                                                              output_8hz=>SAL8HZ);

SEGUNDO_DIVISOR: divisorFrecuenciaMitad PORT MAP(                                                                              CLK=>SAL8HZ,                                                                              SALIDA=>SAL4HZ);

TERCER_DIVISOR: divisorFrecuenciaMitad PORT MAP(                                                                              CLK=>SAL4HZ,                                                                              SALIDA=>SAL2HZ);

CUARTO_DIVISOR: divisorFrecuenciaMitad PORT MAP(                                                                              CLK=>SAL2HZ,                                                                              SALIDA=>SAL1HZ);

                                               output_8Hz <=SAL8HZ;                                               output_4Hz <=SAL4HZ;                                               output_2Hz <=SAL2HZ;         output_1Hz <=SAL1HZ;

end Structural;

2.3.1 Divisor de frecuencia a la mitad:

Page 12: Videojuego FPGA en VHDL

Este componente tiene como entrada la salida del divisor de 8Hz, dicha entrada que es un tren de pulsos la divide cada 4 pulsos para generar un nievo tren de pulsos con la mitad de frecuencia y así sucesivamente con los continuos divisores de frecuencias ya que están dispuestos en serie unos con los otros.

entity divisorFrecuenciaMitad is    Port ( CLK : in std_logic;           SALIDA : out std_logic);end divisorFrecuenciaMitad;

architecture Behavioral of divisorFrecuenciaMitad is                SIGNAL SAL_COPY: STD_LOGIC:='0';                SIGNAL ACU:INTEGER RANGE 0 TO 10:=0;beginSALIDA<=SAL_COPY;PROCESS(CLK)

BEGIN  IF CLK'EVENT AND CLK='1' THEN         ACU<=ACU+1;                END IF;  IF ACU=4 AND SAL_COPY='0' THEN SAL_COPY<='1';  END IF;  IF ACU=4 AND SAL_COPY='1' THEN SAL_COPY<='0';  END IF;                IF ACU=4  THEN ACU<=0;  END IF;

 END PROCESS;

end Behavioral;

2.3.2 Divisor 8 Hz:

Estos tiempos se realizan mediante un contador de pulsos de reloj de la placa que son 50Mhz que son 20 ns, si queremos un tiempo de 8Hz (125.000.000 ns ), entonces no es más que hacer el siguiente cociente:

125.000.000 / 20 = 6.250.000 cuentas

Si 6.250.000 cuentas las dividimos entre dos para hacer un tren de pulsos y dar un pulso alto cada 6.250.000 cuentas, lo que quiere decir que cada 3.125.000 cuentas invertimos el pulso pasando de alto a bajo así generamos un pulso de nivel alto cada 8 Hz.

entity divisor8Hz isPort ( CLK : in std_logic;           output_8hz : out std_logic);end divisor8Hz;

architecture Behavioral of divisor8Hz is                SIGNAL SAL8_COPY: STD_LOGIC:='0';                SIGNAL ACU:INTEGER RANGE 0 TO 35000000:=0;

beginoutput_8hz<=SAL8_COPY;PROCESS(CLK,SAL8_COPY,ACU)

Page 13: Videojuego FPGA en VHDL

BEGIN                IF CLK'EVENT AND CLK='1' THEN           ACU<=ACU+1;                END IF;  IF ACU=3125000 AND SAL8_COPY='0' THEN SAL8_COPY<='1';  END IF;  IF ACU=3125000 AND SAL8_COPY='1' THEN SAL8_COPY<='0';  END IF;                IF ACU=3125000  THEN ACU<=0;  END IF;

 END PROCESS;

end Behavioral;

3.- MONOESTABLE:

Entidad encargada de estabilizar las entradas asincronas y convertirlas en salidas síncronas ya que tiene como entrada habilitadora la salida del selector de frecuencias.

entity monoestable is    Port ( pulsadores : in std_logic_vector(2 downto 0);           enable : in std_logic;           output_mon : out std_logic_vector(2 downto 0)                                                );end monoestable;

architecture Behavioral of monoestable is

beginPROCESS(enable,pulsadores)                               begin                               if ENABLE'EVENT AND enable='1' then output_mon<="000";                               end if;                                                 if pulsadores(0)='1' then output_mon(0)<='1';                                                 end if;                                                               if pulsadores(1)='1' then output_mon(1)<='1';                                                 end if;                                                 if pulsadores(2)='1' then output_mon(2)<='1';                                                 end if;                end PROCESS;end Behavioral;

4.- SALIDA ALEATORIA:

Consiste en la implementación del circuito LFSR propuesto en la documentación del trabajo.

entity salidaAleatoria isPort ( CLK : in std_logic;                                                 rst : in std_logic;                                                 puls_aleat_0 : out std_logic;           puls_aleat_1 : out std_logic;                                                 puls_aleat_2 : out std_logic);

Page 14: Videojuego FPGA en VHDL

end salidaAleatoria;

architecture Behavioral of salidaAleatoria is

begin

PROCESS (rst, clk)

    VARIABLE sr : std_logic_vector(30 DOWNTO 0);

  BEGIN

    IF rst = '1' THEN                   sr := "0100101010110100010110100100110";    ELSIF clk = '1' AND clk'event THEN                   sr := sr(29 DOWNTO 0) & (sr(1) XOR sr(30));                 END IF;

    puls_aleat_0 <= sr(0);    puls_aleat_1 <= sr(1);    puls_aleat_2 <= sr(2);

END PROCESS;end Behavioral;

5.- COMPARADOR:

Componente que como bien dice su nombre compara dos entradas de arrays de vectores de dimensión tres, cuya salida será un flanco de subida si la comparación es correcta y un flanco de bajada si la comparación es errónea.

entity comparador is    Port ( inputa_comp : in std_logic_vector(2 downto 0);           inputb_comp : in std_logic_vector(2 downto 0);           output_comp : out std_logic);end comparador;

architecture Behavioral of comparador is

begin                 PROCESS(inputa_comp,inputb_comp)                                BEGIN

                IF inputa_comp=inputb_comp THEN output_comp<='1';                               ELSE output_comp<='0';                                               END IF;                               END PROCESS;end Behavioral;

6.- CODIFICADOR:

Componente encargado de codificar la señal aleatoria que le llega del LFSR para así encender un único led.

Page 15: Videojuego FPGA en VHDL

entity codificador is Port ( input_cod : in std_logic_vector(2 downto 0);        output_cod : out std_logic_vector(2 downto 0));end codificador;

architecture Behavioral of codificador is

beginprocess(input_cod)                               begin                               if input_cod="000" then output_cod<="000" ;                               elsif input_cod="001" then output_cod<="000" ;                               elsif input_cod="010" then output_cod<="001" ;                               elsif input_cod="011" then output_cod<="001" ;                               elsif input_cod="100" then output_cod<="010" ;                               elsif input_cod="101" then output_cod<="010" ;                               elsif input_cod="110" then output_cod<="100" ;                               else output_cod<="100" ;                               end if;                end process;

end Behavioral;

7.- MULTIPLEXOR ENCENDER LEDS:

Este componente es el encargado de realizar la selección de las entradas que le llegan o bien del monoestable de la salida aleatoria, del monoestable de la salida de los botones y de los comparadores.

La salida del multiplexor representa la salida de los leds que se van a encender y si se ha producido o no el acierto del jugador o lo que es lo mismo si la comparación ha sido correcta.

entity muxEncenderLeds isPort (  A1 : in std_logic;           A2 : in std_logic;           B1 : in std_logic;           B2 : in std_logic;           C1 : in std_logic;           C2 : in std_logic;           D1 : in std_logic;           D2 : in std_logic;           seleccion :  in std_logic;           A : out std_logic;           B : out std_logic;           C : out std_logic;           D : out std_logic);end muxEncenderLeds;

architecture Behavioral of muxEncenderLeds isSIGNAL OUTA_COPY     :              std_logic;SIGNAL OUTB_COPY     :              std_logic;SIGNAL OUTC_COPY     :              std_logic;SIGNAL OUTD_COPY     :              std_logic;

begin

           A <=OUTA_COPY;           B <=OUTB_COPY;

Page 16: Videojuego FPGA en VHDL

           C <=OUTC_COPY;           D <=OUTD_COPY;PROCESS(           A1,A2,B1,B2,C1,C2,D1,D2,seleccion)BEGIN                 IF seleccion='0' THEN                  OUTA_COPY<=A1;                 ELSE                 OUTA_COPY<=A2;                 END IF;                                  IF seleccion='0' THEN                  OUTB_COPY<=B1;                 ELSE                 OUTB_COPY<=B2;                 END IF;

                 IF seleccion='0' THEN                  OUTC_COPY<=C1;                 ELSE                 OUTC_COPY<=C2;                 END IF;

                 IF seleccion='0' THEN                  OUTD_COPY<=D1;                 ELSE                 OUTD_COPY<=D2;                 END IF;                                                                  END PROCESS;end Behavioral;

8.- CONTADOR:

Entidad constituida por una serie de componentes denominados sumador de display, sumador de aciertos y habilitación.

entity contador isPort (        acierto : in std_logic;           rst : in std_logic;           pulsadores : in std_logic_vector (2 downto 0);           d0 : out std_logic_vector(6 downto 0);           d1 : out std_logic_vector(6 downto 0);           d2 : out std_logic_vector(6 downto 0));end contador;

architecture Structural of contador is

component sumadorDeAciertos is    Port ( rst : in std_logic;           salida : out integer range 0 to 9:=0;                                                  carry : out std_logic;               suma : in std_logic);end component;

component habilitacion is    Port ( pulsadores : in std_logic_vector(2 downto 0);

Page 17: Videojuego FPGA en VHDL

           acierto : in std_logic;           salida_habilitacion : out std_logic);end component;

component sumadorDisplays is    Port ( entrada : integer range 0 to 9;           salida : out std_logic_vector(6 downto 0));end component;

signal salida0_copy:integer range 0 to 9;signal salida1_copy:integer range 0 to 9;signal salida2_copy:integer range 0 to 9;

signal carry0_copy:std_logic;signal carry1_copy:std_logic;

signal habilitacion_copy :std_logic;

begin

PRIMER_contador:sumadorDeAciertos PORT MAP(                                                                              rst=>rst,                                                                              carry      =>carry0_copy,                                                                              suma=> habilitacion_copy,                                                                              salida=>salida0_copy);

segundo_contador:sumadorDeAciertos PORT MAP(                                                                              rst=>rst,                                                                              carry      =>carry1_copy,                                                                              suma=> carry0_copy,                                                                              salida=>salida1_copy);

tercer_contador:sumadorDeAciertos PORT MAP(                                                                              rst=>rst,                                                                              suma=> carry1_copy,                                                                              salida=>salida2_copy);

deco0: sumadorDisplays PORT MAP(                                                                              entrada=>salida0_copy ,                                                                              salida=>d0);

deco1: sumadorDisplays PORT MAP(                                                                              entrada=>salida1_copy ,                                                                              salida=>d1);

deco2: sumadorDisplays PORT MAP(                                                                              entrada=>salida2_copy ,                                                                              salida=>d2);

habilit: habilitacion PORT MAP(                                                                              pulsadores=>pulsadores ,                                                                              acierto=>acierto,                                                                              salida_habilitacion=>habilitacion_copy);

end Structural;

Page 18: Videojuego FPGA en VHDL

8.1 Sumador de aciertos:

Contador de pulsos que te llegan de la salida del componente habilitación, el cual tiene una entrada del botón reset para poner a cero el contador. El sumador está constituido por 3 sumadores encargados cada uno de realizar hasta un total de 999 aciertos, ya que cuando el sumador de unidad se desborda tiene una salida de carrier que le llega al siguiente sumador y así sucesivamente.

entity sumadorDeAciertos is    Port ( rst : in std_logic;           salida : out integer range 0 to 9:=0;                                                  carry : out std_logic;               suma : in std_logic);end sumadorDeAciertos;

architecture Behavioral of sumadorDeAciertos is                signal cont_copy: integer range 0 to 9 :=0 ;                signal carry_copy: std_logic:='0' ;begin                salida<=cont_copy;                                                carry<= carry_copy;                 process(suma,rst)                begin                               if suma'event and suma='1' and rst='0' then                                               if cont_copy<9 then                                                               cont_copy<=cont_copy+1;                                                               carry_copy<='0';                                               end if;                                               if cont_copy=9 then                                                carry_copy<='1';                                                               cont_copy<=0;                                               end if;                               end if;

                               if rst='1' then                                 cont_copy<=0;                                carry_copy<='0';                                 end if;                                               end process;

end Behavioral;

8.2 Sumador displays:

Es un codificador que tiene como entrada la suma de los aciertos y como salida la codificación que le corresponde a cada número respecto a los displays de la placa.

entity sumadorDisplays is    Port ( entrada : integer range 0 to 9;           salida : out std_logic_vector(6 downto 0));end sumadorDisplays;

architecture Behavioral of sumadorDisplays is

begin

Page 19: Videojuego FPGA en VHDL

process(entrada)begin                case entrada is                               when 0 =>                                               salida <="0000001";                               when 1 =>                                               salida <="1001111";                               when 2 =>                                               salida <="0010010";                               when 3 =>                                               salida <="0000110";                               when 4 =>                                               salida <="1001100";                               when 5 =>                                               salida <="0100100";                               when 6 =>                                               salida <="0100000";                               when 7 =>                                               salida <="0001111";                                when 8 =>                                               salida <="0000000";                               when 9 =>                                               salida <="0000100";                               when others =>                                               salida <="1111110";                end case;                 end process;

end Behavioral;

8.3 Habilitación:

Componente encargado de asegurarnos que el usuario a pulsado algún botón y si el botón a sido pulsado y se ha producido un acierto, este saca un pulso alto, el cual será contado por el sumador de aciertos.

entity habilitacion is    Port ( pulsadores : in std_logic_vector(2 downto 0);           acierto : in std_logic;           salida_habilitacion : out std_logic);end habilitacion;

architecture Behavioral of habilitacion is

begin                  process(acierto,pulsadores)                  begin                  IF  pulsadores/="000" AND acierto='1' THEN salida_habilitacion<=acierto;                  end if;                  if pulsadores="000" then salida_habilitacion<='0';                  END IF;                                   end process;

end Behavioral;

9.- MULTIPLEXOR DISPLAY:

Page 20: Videojuego FPGA en VHDL

La disposición de la placa respecto a los display no es tener una un array de conexiones para cada display, sino tener un solo array de conexiones para los tres display y multiplexar la salida. Para ellos se realiza un multiplexor que tenga como entradas las señales numéricas de los tres display para luego conmutarlos a una velocidad que al ojo humano piense que es continuo (aprox 15 fps).

Para dicha conmutación se ha realizado un componente denominado conmutador display el cual ataca a las entradas de selección del multiplexor de displays.

entity muxDisplays is    Port ( d0 : in std_logic_vector(6 downto 0);           d1 : in std_logic_vector(6 downto 0);           d2 : in std_logic_vector(6 downto 0);           display : out std_logic_vector(6 downto 0);           a : in std_logic;           b : in std_logic;           c : in std_logic);end muxDisplays;

architecture Behavioral of muxDisplays is

beginprocess(a,b,c,D0,D1,D2)                                begin                                               if c='1' and b='1' and a='0' then display <= d0;                                               end if;                                               if c='1' and b='0' and a='1' then display <= d1;                                               end if;                                               if c='0' and b='1' and a='1' then display <= d2;                                               end if;                                                                  end process;

end Behavioral;

10.- CONMUTADOR DISPLAY:

Teniendo en cuenta que los displays se activan mediante lógica negativa ( enable = 0 ), se conmutan estos cada cierto tiempo, para ellos se ha realizado un contador de pulsos de reloj de la placa.

entity conmutadorDisplay is    Port ( CLK : in std_logic;           A : OUT std_logic;           B : OUT std_logic;                                                 C : OUT std_logic);end conmutadorDisplay;

architecture Behavioral of conmutadorDisplay is                               SIGNAL ACUMULADOR:INTEGER RANGE 0 TO 300000:=0;                  SIGNAL A_COPY:std_logic:='0';                  SIGNAL B_COPY:std_logic:='1';                  SIGNAL C_COPY:std_logic:='1';beginPROCESS(CLK) BEGINIF CLK'EVENT AND CLK='1' THEN           ACUMULADOR<=ACUMULADOR+1;IF ACUMULADOR=299999 THEN ACUMULADOR<=0;END IF;IF ACUMULADOR<100000 THEN 

Page 21: Videojuego FPGA en VHDL

                                               A_COPY<='0';                                               B_COPY<='1';                                               C_COPY<='1';

END IF;IF ACUMULADOR>99999 AND ACUMULADOR<200000 THEN                                                A_COPY<='1';                                               B_COPY<='0';                                               C_COPY<='1';END IF;

IF ACUMULADOR>199999 THEN                                                A_COPY<='1';                                               B_COPY<='1';                                               C_COPY<='0';END IF;

END IF;

END PROCESS;

                                               A<=A_COPY;                                               B<=B_COPY;                                               C<=C_COPY;

end Behavioral;

Disposición ordenada de bloques y señales

Podemos ver que se ha dispuesto un documento anexo en pdf en el apartado descarga de este link, donde se encuentran las señales, entradas y salidas  y bloques de forma ordenada para poder seguir de forma fácil y sencilla todo el proceso.