Videojuego FPGA en VHDL
Videojuego FPGA en VHDL
Realizaremos paso a paso un sencillo ejemplo de entretenimiento para aprender a programar nuestra
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
FPGA, para ello usaremos la tarjeta de Xilinxs, Spartan III Starter Kit.
Kit.
Objetivo
Objetivo
Se trata de implementar un sencillo videojuego que ponga a prueba los reflejos del jugador. El 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
del juego se trata de atrapar a los escurridizos bits que irán apareciendo de forma aleatoria en los LED
(LD0, LD1, LD2). Para
(LD0, LD1, LD2). Para ello habrá que accionar los pulsadores (BTN0, BTN1, BTN2) mientras los LED
ello habrá que accionar los pulsadores (BTN0, BTN1, BTN2) mientras los LED
correspond
correspondientes estén todavía encendidos. La partida
ientes estén todavía encendidos. La partida se iniciará tras pulsar el
se iniciará tras pulsar el Reset del sistema (BTN3)
Reset del sistema (BTN3)
y durará 30 segundos. Los led permanecerán quietos durante 0.25 segundos antes de pasar a su siguiente
y durará 30 segundos. Los led permanecerán quietos durante 0.25 segundos antes de pasar a su siguiente
configuración.
configuración.
El visualizador de cuatro dígitos mostrará en todo momento el número de bits atrapados desde el
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
comienzo de la partida.No será válido dejar los pulsadores permanentemente actuados (emplear
monoestabl
monoestable no r
e no redisparable en estas entradas, por ejemplo,
edisparable en estas entradas, por ejemplo, versiones basadas en el circuito antirrebote
versiones basadas en el circuito antirrebote
que se menciona en las sugerencias).
que se menciona en las sugerencias).
Para generar la
Para generar la secuenci
secuencia pseudoaleatoría se
a pseudoaleatoría se empleará un LFSR
empleará un LFSR (Linear FeedBackShift
(Linear FeedBackShiftRegister). Los
Register). Los
circuitos LFSR se utilizan en infinidad de sistemas electronicos para generar secuencias pseudoaleatorias
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
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
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.
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
La elección de las salidas reañimentadas es fundamental para conseguir una máxima longitud de la
secuencia sin repeticione
secuencia sin repeticiones. Para
s. Para este trabajo emplearemo
este trabajo emplearemos un
s un LFSR de 31
LFSR de 31 bits realimentando las salidas
bits realimentando las salidas
2 y 30
2 y 30 (numerandol
(numerandolas desde cero),
as desde cero), lo que generará
lo que generará secuenc
secuencias sin repeticiones de a
ias sin repeticiones de aproximad
proximadamente
amente
2.200 millones de números. Utilizaremos las tres de menor peso como patrón para encender los led.
2.200 millones de números. Utilizaremos las tres de menor peso como patrón para encender los led.
Una característi
Una característica de los LFSR
ca de los LFSR es que quedan bloqueados si su contenido es cero. P
es que quedan bloqueados si su contenido es cero. P or ello es necesario
or ello es necesario
inicializarlos con una semilla (un valor distinto de cero).
inicializarlos con una semilla (un valor distinto de cero).
Mejoras realizadas:
Mejoras realizadas:
Inclusión de varios niveles de dificultad, aumentando y disminiyundo el tiempo que los leds permanecen
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.
Incluir varios niveles de dificultad aumentando o disminuyendo el número de leds que pueden
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
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.
contendrían los led a encender. La selección se realizará mediante los interruptores deslizantes.
Métodos empleados:
Métodos empleados:
Usar contadores BCD con acarreo y
Usar contadores BCD con acarreo y permiso para almacenar la puntuación. El contador sólo
permiso para almacenar la puntuación. El contador sólo contará en
contará en
los flancos de subida de se señal de reloj cuando el permiso esté a 1. El acarreo valdrá 1 mientras el
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
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.
será el permiso del siguiente.
Emplear un único decodificador de 7 segmentos y la técnica de multiplexación (ver manual) para
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.
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
Usar un prescaler o divisor que genere a partir de los 50MHz disponibles en la placa las frecuencias
necesarias para la aplicación.
necesarias para la aplicación.
Incluir circuitos antirrebote en las entradas conectadas a pulsadores (ver
Incluir circuitos antirrebote en las entradas conectadas a pulsadores (ver "lenguaje Template
"lenguaje Templates"-
s"->"VHDL"->"Syn
>"VHDL"->"SynthesisTemplate
thesisTemplates"->"Debouncecircu
s"->"Debouncecircuit" en
it" en la
la herram
herramienta
ienta Xilinx ISE).
Xilinx ISE).
Manual
Manual
de
de
usuario
usuario
Primeramente vamos a explicar el procedimiento lineal que sigue el sistema para realizar el videojuego.
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
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.
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
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
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
a la vez, estas opciones de juego las seleccionaremos con los deslizadores de la tarjeta, tal y como
aparece a continuación:
aparece a continuación:
Duración de juego:
Duración de juego:
SW1 SW0 SW1 SW0 10 10 SEG SEG 0 0 00 30 30 SEG SEG 0 0 11 40 40 SEG SEG 1 1 00 60 60 SEG SEG 1 1 11Velocidad de los leds:
Velocidad de los leds:
SW3 SW2 SW3 SW2 1 1 HZ HZ 0 0 00 2 2 HZ HZ 0 0 11 4 4 HZ HZ 1 1 00 8 8 HZ HZ 1 1 11
Número de leds:
Número de leds:
SW4 SW4 UN UN LED LED 11 VARIOSHay 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 s eñ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 si ga 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.
F
uncionami
e
n
t
o
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
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 a
v
anzado
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.1Selector tiempo de juego:
Entidad que contiene los cinco componentes ya citados anteriormente.
entity selector TiempoDeJuego isPort ( CLK : in std_logic; r st : in std_logic;
seleccion:IN STD _ LOGIC _VECTOR(1 DOWNTO 0); output_tiempo_juego : out std_logic);
end selector TiempoDeJuego;
architecture STRUCTURAL of selector TiempoDeJuego is component contador 10seg is
Port ( CLK : in std_logic; r st : in std_logic;
output_ 10seg : out std_logic); end component;
component contador30seg is Port ( CLK : in std_logic;
r st : in std_logic;
output_30seg : out std_logic); end component;
component contador40seg is Port ( CLK : in std_logic;
r st : in std_logic;
output_40seg : out std_logic); end component;
component contador60seg is Port ( CLK : in std_logic;
r st : in std_logic;
output_60seg : out std_logic); end component;
component muxSelector TiempoDeJuego is Port ( 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:contador 10seg PORT MAP(
CLK=>CLK,
output_ 10seg=>SAL10S, r st=>r st);
TIEMPO _30S:contador30seg PORT MAP(
CLK=>CLK,
output_30seg=>SAL30S, r st=>r st);
TIEMPO _40S:contador40seg PORT MAP(
CLK=>CLK,
output_40seg=>SAL40S, r st=>r st);
TIEMPO _ 1M:contador60seg PORT MAP(
CLK=>CLK,
output_60seg=>SAL1M, r st=>r st);
SELECTOR:muxSelector TiempoDeJuego PORT MAP(
seleccion=>seleccion, input_ 10seg=>SAL10S, input_30seg=>SAL30S, input_40seg=>SAL40S, input_60seg=>SAL1M, salida _tiempo_juego=>SAL _ MUX);
output_tiempo_juego<= SAL _ MUX; endStr uctur al;
1.2
Cont
a
dor
10segundos:
Contador es un acumulador de ciclos de reloj que pone a uno una salida el tiempo de dicho contador.
entity contador 10seg isPort ( CLK : in std_logic; r st : in std_logic;
output_ 10seg : out std_logic); end contador 10seg;
architecture Behavior al of contador 10seg is
SIGNAL SALIDA _ TIEMPO _ COPY: STD _ LOGIC:='0'; SIGNAL ACU1:INTEGER RANGE 0 TO 500000000:=0; begin
output_ 10seg<=SALIDA _ TIEMPO _ COPY ; PROCESS(CLK,r st,salida _tiempo_copy,ACU1) BEGIN
IF r st'EVENT AND r st='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 Behavior al;
1.3
Cont
a
dor
30segundos:
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; r st : in std_logic;
output_30seg : out std_logic); end contador30seg;
architecture Behavior al of contador30seg is SIGNAL SALIDA _ TIEMPO _ COPY: STD _ LOGIC;
SIGNAL ACU2:INTEGER RANGE 0 TO 1500000000:=0; begin
output_30seg<=SALIDA _ TIEMPO _ COPY ;
PROCESS(CLK,r st,SALIDA _ TIEMPO _ COPY,ACU2) BEGIN
IF r st'EVENT AND r st='0'THEN SALIDA _ TIEMPO _ COPY<='1'; END IF;
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 ; endBehavioral;
1.4
Cont
a
dor
40segundos:
Contador es un acumulador de ciclos de reloj que pone a uno una salida el tiempo de dicho contador.
entity contador40seg isPort ( CLK : in std_logic; r st : in std_logic;
output_40seg : out std_logic); end contador40seg;
architecture Behavior al of contador40seg is SIGNAL SALIDA _ TIEMPO _ COPY: STD _ LOGIC;
SIGNAL ACU3:INTEGER RANGE 0 TO 2000000000:=0; begin
output_40seg<=SALIDA _ TIEMPO _ COPY ;
PROCESS(CLK,r st,SALIDA _ TIEMPO _ COPY,ACU3) BEGIN
IF r st'EVENT AND r st='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 ; endBehavior al;
1.5
Cont
a
dor 6
0segundos:
Contador es un acumulador de ciclos de reloj que pone a uno una salida el tiempo de dicho contador.
entity contador60seg isPort ( CLK : in std_logic; r st : in std_logic;
output_60seg : out std_logic); end contador60seg;
architecture Behavior al of contador60seg is SIGNAL SALIDA _ TIEMPO _ COPY: STD _ LOGIC;
SIGNAL ACU4:INTEGER RANGE 0 TO 1500000000:=0; SIGNAL ACU5:INTEGER RANGE 0 TO 10:=0;
--SIGNAL ACU5:REAL RANGE 0 TO 10:=0; begin
output_60seg<=SALIDA _ TIEMPO _ COPY ;
PROCESS(CLK,r st,SALIDA _ TIEMPO _ COPY,ACU4,ACU5) BEGIN
IF r st'EVENT AND r st='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 ; endBehavior al;
1.
6 Multiplexor selector de tiempo:
Selector del contador que vamos a aplacar a nuestro juego, par a ello las entr adas de
selección son los deslizadores cero y uno
.entity muxSelector TiempoDeJuego is Port ( 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 muxSelector TiempoDeJuego;
architecture Behavior al of muxSelector TiempoDeJuego is SIGNAL O _ COPY: STD _ LOGIC;
begin
salida _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;
END IF; END PROCESS; endBehavior al;
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 frecuenci
a
s 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 Selector FrecuenciaLeds 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 Selector FrecuenciaLeds;
architecture STRUCTURAL of Selector FrecuenciaLeds is component muxSelector FrecuenciaLeds is
Port ( 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 is
Port ( 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:muxSelector FrecuenciaLeds PORT MAP(
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 frecuenci
a
s 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 muxSelector FrecuenciaLeds is Port ( 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 muxSelector FrecuenciaLeds;
architecture Behavior al of muxSelector FrecuenciaLeds is SIGNAL O _ COPY: STD _ LOGIC;
begin salida _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; endBehavior al;
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 Str uctur al of preescaler is component divisor8Hz is
Port ( CLK : in std_logic;
output_8hz : out std_logic); end component;
component divisor FrecuenciaMitad 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: divisor FrecuenciaMitad PORT MAP(
CLK=>SAL8HZ, SALIDA=>SAL4HZ); TERCER _ DIVISOR: divisor FrecuenciaMitad PORT MAP(
CLK=>SAL4HZ, SALIDA=>SAL2HZ); CUARTO _ DIVISOR: divisor FrecuenciaMitad PORT MAP(
CLK=>SAL2HZ, SALIDA=>SAL1HZ); output_8Hz <=SAL8HZ; output_4Hz <=SAL4HZ; output_ 2Hz <=SAL2HZ; output_ 1Hz <=SAL1HZ; endStr uctur al;
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 divisor FrecuenciaMitad is Port ( CLK : in std_logic;
SALIDA : out std_logic); end divisor FrecuenciaMitad;
architecture Behavior al of divisor FrecuenciaMitad is SIGNAL SAL _ COPY: STD _ LOGIC:='0'; SIGNAL ACU:INTEGER RANGE 0 TO 10:=0; begin
SALIDA<=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; endBehavior al;
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 is Port ( CLK : in std_logic;
output_8hz : out std_logic); end divisor8Hz;
architecture Behavior al of divisor8Hz is
SIGNAL SAL8_ COPY: STD _ LOGIC:='0';
SIGNAL ACU:INTEGER RANGE 0 TO 35000000:=0; begin
PROCESS(CLK,SAL8_ COPY,ACU) 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; endBehavior al;
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 Behavior al of monoestable is begin
PROCESS(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 Behavior al;
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;
r st : in std_logic;
puls _ aleat_ 0 : out std_logic; puls _ aleat_ 1 : out std_logic;
puls _ aleat_ 2 : out std_logic); end salidaAleatoria;
architecture Behavior al of salidaAleatoria is begin
PROCESS (r st, clk)
V ARIABLE sr : std_logic_vector (30 DOWNTO 0); BEGIN
IF r st = '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; endBehavior al;
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 compar ador 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 compar ador;
architecture Behavior al of compar ador 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 Behavior al;
6.- CODIFICADOR:
Componente encargado de codificar la señal aleatoria que le llega del LFSR para así encender un único
led.
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 Behavior al of codificador is begin
process(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; endBehavior al;
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 compar ación ha sido correcta.entity muxEncender Leds is Port ( 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 muxEncender Leds;
architecture Behavior al of muxEncender Leds is SIGNAL 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;
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 Behavior al;
8.- CONTADOR:
Entidad constituida por una serie de componentes denominados sumador de display, sumador de aciertos
y habilitación.
entity contador is
Port ( acierto : in std_logic; r st : 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 Str uctur al of contador is component sumador De Aciertos is
Port ( r st : in std_logic;
salida : out integer r ange 0 to 9:=0;
carry : out std_logic; suma : in std_logic);
end component;
component habilitacion is
acierto : in std_logic;
salida _habilitacion : out std_logic); end component;
component sumador Displays is
Port ( entr ada : integer r ange 0 to 9;
salida : out std_logic_vector (6 downto 0)); end component;
signal salida0 _copy:integer r ange 0 to 9; signal salida1 _copy:integer r ange 0 to 9; signal salida2 _copy:integer r ange 0 to 9; signal carry0 _copy:std_logic;
signal carry1 _copy:std_logic; signalhabilitacion_copy :std_logic; begin
PRIMER _contador :sumador De Aciertos PORT MAP( r st=>r st,
carry =>carry0 _copy, suma=>habilitacion_copy, salida=>salida0 _copy); segundo_contador :sumador De Aciertos PORT MAP(
r st=>r st,
carry =>carry1 _copy, suma=> carry0 _copy, salida=>salida1 _copy); tercer_contador :sumador De Aciertos PORT MAP(
r st=>r st,
suma=> carry1 _copy, salida=>salida2 _copy); deco0: sumador Displays PORT MAP(
entr ada=>salida0 _copy , salida=>d0);
deco1: sumador Displays PORT MAP(
entr ada=>salida1 _copy , salida=>d1);
deco2: sumador Displays PORT MAP(
entr ada=>salida2 _copy , salida=>d2);
habilit: habilitacion PORT MAP(
pulsadores=>pulsadores , acierto=>acierto,
salida _habilitacion=>habilitacion_copy); endStr uctur al;
8.1
Sum
a
dor de
a
ciertos:
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 su mador 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 sumador De Aciertos is Port ( r st : in std_logic;
salida : out integer r ange 0 to 9:=0;
carry : out std_logic; suma : in std_logic);
end sumador De Aciertos;
architecture Behavior al of sumador De Aciertos is signal cont_copy: integer r ange 0 to 9 :=0 ; signal carry_copy: std_logic:='0' ;
begin
salida<=cont_copy;
carry<= carry_copy; process(suma,r st)
begin
if suma'event and suma='1' and r st='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 r st='1' then cont_copy<=0; carry_copy<='0'; end if; end process; endBehavior al;
8.2
Sum
a
dor displ
ay
s:
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 sumador Displays is
Port ( entr ada : integer r ange 0 to 9;
salida : out std_logic_vector (6 downto 0)); end sumador Displays;
begin process(entr ada) begin case entr ada 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 other s => salida <="1111110"; end case; end process; endBehavioral;
8.3
H
ab
ilit
a
ció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.
entityhabilitacionisPort ( pulsadores : in std_logic_vector (2 downto 0); acierto : in std_logic;
salida _habilitacion : outstd_logic); endhabilitacion;
architecture Behavior al 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; endBehavior al;
9.- MULTIPLEXOR DISPLAY:
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 Behavior al of muxDisplays is begin
process(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; endBehavior al;
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 conmutador Display is Port ( CLK : in std_logic;
A : OUT std_logic; B : OUT std_logic;
C : OUT std_logic); end conmutador Display;
architecture Behavior al of conmutador Display 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'; begin PROCESS(CLK) BEGIN
IF CLK'EVENT AND CLK='1' THEN ACUMULADOR<=ACUMULADOR+1; IF ACUMULADOR=299999 THEN ACUMULADOR<=0;
END IF; IF ACUMULADOR<100000 THEN 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; endBehavior al;
D