Introducción a la Lógica Programable (4) - Primer ejemplo práctico
¡Hola a todos los que están siguiendo este curso!
Releyendo las tres primeras lecciones veo que hasta ahora les he dado sólo teoría, y acorde al espíritu de la revistucha Lupín, hago una pequeña pausa para introducir el primer ejemplo práctico. Por supuesto que en las lecciones venideras seguiremos viendo tanto teoría como práctica.
Les recuerdo que, si tienen dudas, propuestas, comentarios, etc. sobre este curso, pueden enviarlas de cualquiera de estas dos maneras:
- Por correo electrónico a pagina_resorte@yahoo.com
- A través del grupo de Facebook: La página web de Resorte
Ejemplo de registro en System Verilog
Como queremos construir lógica programable, tenemos que aprender la manera de decirle a nuestro FPGA cuál es la lógica que queremos realizar. Para eso se utiliza lo que se denomina un lenguaje de descripción de Hardware. ¡Pongan atención en ésto! Aunque System Verilog es parecido a lenguajes de programación como C, su objetivo principal es muy diferente. Usaremos System Verilog para decirle al FPGA que hardware queremos que implemente, que es algo muy distinto a las instrucciones que ejecuta un microprocesador.
Si bien System Verilog se puede usar para otras funciones además de describir hardware, cuando lo usamos para describir hardware tenemos que tener siempre bien en claro que tipo de compuertas y flip-flops van a "nacer" como resultado de nuestro código en Verilog. Un código escrito para crear compuertas y flip-flops se dice que es un código sintetizable.
Un registro no es más que varios flip-flops trabajando juntos. Nosotros construiremos un registro de cuatro bits, cuyos contenidos pueden ser desde 0000 hasta 1111.
Y sin más introducciones, veamos nuestro primer ejemplo en System Verilog:
1 2 3 4 5 6 7 8 9 10 | module registro ( input bit clk, input bit [3:0] d, output bit [3:0] q ); always_ff @(posedge clk) q <= d; endmodule |
Las líneas de 1 a 5 definen la interfaz de nuestro módulo, es decir, cuáles son sus entradas y salidas. Como dijimos en lecciones anteriores, trabajaremos siempre con diseños síncronos, por lo que la primer entrada es nuestro reloj (clk).
Como nuestro registro es de cuatro bits, tanto la entrada 'd' como la salida 'q' son vectores de cuatro bits. El vector 'd' incluye a los bits d[3], d[2], d[1] y d[0].
Todas las entradas y las salidas han sido definidas de tipo 'bit'. Esto quiere decir que sólo pueden tener valores de '0' o '1'.
Una vez finalizada de definir la interfaz (noten que cada línea de la definición de interfaz termina con una coma, salvo la última), es decir, cuando se cierra el paréntesis con punto y coma en la línea cinco, pasamos a describir qué es lo que queremos que haga nuestra lóigca.
Para eso usamos el bloque "always_ff" que como su nombre lo indica, se usa para describir un flip-flop o, como en nuestro caso, un grupo de flip-flops.
Lo que nos está diciendo la instrucción es que cada vez que haya un flanco positivo (posedge) de la señal de reloj clk, copiemos la entrada d a la salida q.
Y listo, eso es todo para nuestro primer ejemplo.
Simulación de nuestro módulo "registro" en System Verilog
Una de las grandes ventajas de usar lenguajes de descripción de hardware, como System Verilog, es que podemos simular fácilmente en nuestra compu el comportamiento de nuestro FPGA.
Para ello necesitamos una herramienta de simulación (en nuestro curso utilizaremos Modelsim, más abajo explico de dónde bajarlo gratis) y un entorno de simulación que incluye a nuestro(s) módulo(s) y a un bloque especial que ingresa señales de estímulo y verifica las salidas de nuestro sistema.
A este bloque especial se lo denomina en inglés "testbench" (banco de pruebas). A continuación les muestro el banco de pruebas el módulo "registro":
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | `timescale 10 ns/1 ns // time-unit = 10 ns, precision = 1 ns module tb_reg; bit clk; bit [3:0] d; bit [3:0] q; always #25 clk <= ~clk; registro DUT ( .clk, .d, .q ); initial begin clk <= 0; d <= 4'b0; #50 d <= 4'b0010; #100 d <= 4'b1011; #100 $stop; end endmodule |
Las líneas número 1 define la base de tiempo de la simulación, que es de 10 ns, y la precisión, de 1 ns. Volveremos a este punto en unas líneas más.
La línea 3 define el nombre del módulo que realiza la simulación. Es común usar las letras "tb" en el nombre de un testbench. Como pueden ver, el banco de pruebas no tiene entradas ni salidas, ni las necesita, porque todo lo que hace es inyectar señales a nuestro módulo "registro".
Las líneas 5 a 7 generan señales internas que serán conectadas a nuestro módulo.
Las líneas nueve y diez generan una señal de reloj que cambia cada 25 unidades de tiempo, como nuestra unidad de tiempo es 10 ns, el semi-período del reloj es de 250 ns y por lo tanto, su período es de 500ns. Haciendo las cuentas nos sale que es una señal de 2MHz.
Las líneas 12 a 16 instancian un módulo de tipo "registro" y le dan como nombre "DUT". Este nombre es muy usado, viene de las siglas en inglés "Device Under Test" (dispositivo bajo prueba).
System Verilog tiene una forma abreviada de conectar señales a puertos, si el puerto tiene el mismo nombre que la señal, se coloca para cada puerto una línea que comienza con un punto y se termina con el nombre del puerto. Ésto lo pueden ver en la figura a continuación:
Por último, el bloque "initial" nos permite entregar una secuencia de valores a la entrada del registro para ver cómo se comporta. En general, en un testbench escribiremos código que nos permita verificar nuestro diseño de forma automática, cosa que ya veremos en ejemplos sucesivos. En esta primer entrega, sólo visualizaremos las señales de entrada y salida a nuestro módulo "registro".
Algunas aclacraciones sobre el código del banco de pruebas:
La notación 4'b0010 en la línea 23 nos dice que el bus de entrada d recibirá una palabra de 4 bits de ancho cuyo valor es 0010.
El comando $stop en la línea 27 detiene la simulación. Si no incluimos una condición de detención en el banco de pruebas, este se podría ejecutar en forma indefinida. Siempre conviene tener una condición de detención en el testbench.
Una vez que verificamos nuestro diseño con Modelsim, obtenemos las siguientes formas de onda:
Comentarios
Publicar un comentario