Revisado por: Holguer A. Becerra
Objetivos
- Dar un repaso general a la sintaxis de la descripción de hardware en Verilog
- Describir algunos dispositivos útiles durante el desarrollo del curso como multiplexores, contadores, sincronizadores y divisores de frecuencia
Procedimiento
Para empezar es necesario crear un proyecto, esto se hará a través del System Builder.
Al ejecutarlo se abrirá una interfaz como la de la siguiente figura, es importante notar las partes de la tarjeta seleccionadas, que son las que usaremos en nuestro proyecto. Llamaremos a este ejemplo test_clase1
Después de hacer clic en Generate se nos abrirá una ventana preguntando dónde deseamos guardar, preferiblemente dentro de una carpeta destinada para todos los proyectos del curso, y seleccionamos guardar.
Ya podemos salir del System builder con el botón Exit. Para empezar a trabajar en nuestro proyecto tenemos que buscar en la ubicación que elegimos (por default estará en la misma carpeta del System builder en una subcarpeta llamada CodeGenerated) y abrirlo con el software quartus II.
Nos abrirá algo como esto:
Al hacer doble clic en test_clase1 en el Project Navigator se nos abrirá el archivo Verilog que se puede visualizar en el área central.
En el código podemos encontrar las declaraciones de las entradas y salidas que dejamos seleccionadas en la ventana del System Builder.
Este archivo representa el chip principal, dentro del cual describiremos los elementos que deseamos para esta práctica, comenzando por un multiplexor.
Descripción de un multiplexor
Estando en la misma ventana que acabamos de ver, seleccionamos Nuevo > Verilog HDL File > OK
Al describir cualquier elemento primero declaramos el módulo, que será llamado igual que el archivo sobre el que estamos trabajando, en este caso lo declararemos como ejem_mux
Seguimos indicando cuáles serán las entradas y salidas de nuestro multiplexor, usaremos las cuatro entradas como constantes, y los selectores como “variables”, se declaran así:
Cabe aclarar que el selector tiene dos bits, ya que son necesarios para abarcar las 4 posibles entradas a multiplexar, y la salida tiene 8 bits tal como se indicó en la figura.
El siguiente paso es asignar la salida, para esto usaremos condiciones, que nos permitirán según un valor fijado en el selector, poner la salida deseada.
Esta es la descripción completa del multiplexor, ahora veremos cómo instanciarlo dentro del chip principal, es importante prestar mucha atención a este proceso, ya que lo usaremos para los siguientes elementos que describiremos.
En primer lugar crearemos la instanciación, esto en File > Create/Update > Create Verilog Instantiation Template Files for Current File
Esto habrá creado un archivo llamado ejem_mux_inst.v en la carpeta del proyecto, podemos abrirlo con cualquier editor de texto
El texto será así:
Se copiará esto dentro del chip principal, poniendo un nombre de nuestra elección y borrando lo que hay dentro de los paréntesis, es allí donde indicaremos que entradas y salidas del chip principal corresponden.
Para este caso se usaron dos interruptores para los selectores, y ocho leds para visualizar la salida.
Ya tenemos listo nuestro multiplexor dentro del chip principal con todas las conexiones hechas, si queremos ver y comprobar gráficamente que todo esté en su lugar vamos a RTL viewer desde la sección de tareas y le damos clic derecho > open:
Desde la ventana del RTL Viewer revisamos el diagrama esquemático, notando que todo está tal cual lo describimos.
Continuamos con Analysis & Synthesis, Fitter y Assembler. Si no aparece ningún error y el proceso finaliza exitosamente sabremos que todo ha sido descrito correctamente y que nuestro diseño se ajusta a las características de la FPGA que estamos utilizando.
Para revisar el módulo terminado e implementarlo en los siguientes proyectos, se puede descargar de aquí.
Descripción de un contador
Un contador se puede construir con un Flip-Flop tipo D y un sumador, los cuales se conectarían de la siguiente manera:
Se declara el módulo con el nombre contador y se guarda el archivo con el mismo nombre, luego se declaran las entradas y las salidas, resultando algo como esto:
Las entradas como se puede ver a la izquierda del diagrama corresponden a una señal de reloj y una de reset para reiniciar el conteo. A la salida tenemos 8 bits que irán cambiando a medida que se vaya contando.
Aquí se introduce un nuevo concepto, y es la descripción del flip-flop tipo D, que simplemente se hace a través de un registro de 8 bits que llamaremos conteíto. Los registros siempre deben ser inicializados.
reg [7:0]conteito=8'd0;
Pero aparece una situación particular cuando se usan registros, es necesario usar un proceso llamado always para asignarle su comportamiento, también se trabaja con lógica secuencial en vez de combinacional, por lo que las asignaciones se harán con el símbolo <=.
Al usar always, se requiere una señal como argumento para realizar el proceso a cada cambio de esta, para este caso realizaremos el proceso contar siempre que se tenga un flanco de reloj en el flip-flop, por lo que se describe así:
Lo que vamos a hacer para contar es ir aumentando en uno el registro conteíto, esto sólo interrumpido cuando se pone un valor bajo en la entrada reset (activo bajo).
La lógica descrita fue:
Ya listo el contador, genera la instanciación igual que con el multiplexor.
Con esto, instanciamos el contador en el chip principal, usando el reloj de la FPGA para la señal de reloj, una Key para el reset y ocho leds para visualizar el conteo.
Revisando el RTL, encontramos que nuestras conexiones estuvieron bien descritas y que la descripción fue exitosa.
No olvidar el proceso de análisis y síntesis, enrutar y ensamblar para verificar que todo esté perfectamente diseñado y descrito.
El módulo de verilog se puede descargar aquí.
Descripción de un sincronizador
A veces, cuando una señal de entrada empieza después del flanco que se analiza y termina antes del siguiente flanco a analizar ésta pasa inadvertida, perdiéndose información importante o dejando sin ejecutar alguna acción que puede resultar en un grave problema para el sistema, para esto fueron diseñados los sincronizadores.
Un sincronizador sirve de puente entre dos dispositivos con diferentes frecuencias, y consta de dos entradas, una de reloj y otra de la señal asíncrona que queremos recuperar, a la salida tenemos una señal sincronizada que nos evitará cualquier problema de este tipo.
Para esta descripción nuestras entradas y salidas serán las que declaramos, una entrada asíncrona, una de reloj y la salida síncrona
wire clk_25mhz;always@(posedge FPGA_CLK1_50)beginclk_25mhz<=~clk_25mhz;end
Ya que como se mencionó esto sólo permite una pequeña cantidad de posibilidades, fue necesario conocer otro diseño de división de frecuencias.