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:


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:


Cuándo llega el segundo pulso de reloj (primer cursor @750 ns), la entrada "0010" aparee a la salida. Si recuerdan en lecciones anteriores, mencionamos que a un FF le lleva un cierto tiempo presentar los datos a la salida. Las herramientas de simulación, salvo que se los pidamos expresamente, ignoran estos tiempos, por eso la salida cambia "en el mismo momento" en que el reloj cambia de 0 a 1. Esto puede confundir un poco al principio pero conviene acostumbrarse a visualizar así nuestro diseño.

Cuando llega un pulso @1250ns la salida no cambia porque la entrada tampoco lo ha hecho.

Finalmente, @1750ns la salida cambia a 1011 reflejando, nuevamente, el estado de la entrada,

¿Fácil, no?

Como bajar en forma gratuita (y legal) la herramienta Modelsim

Los fabricantes más importantes de componentes FPGA en el mundo actual son tres: Xilinx, Intel y Lattice.

Intel posee una división de FPGA llamada Intel PSG. Durante años se llamó Altera (podrán encontrar mucha información en la Internet usando todavía ese nombre) pero hace unos años Intel compró a esa compañía cambiándole su nombre a Intel PSG,

En el sitio web de Intel PSG se puede bajar la versión "Lite" del Modelsim sin ningún costo. Para ello hay que inscribirse previamente.

Una vez han bajado el Modelsim Lite, pueden usar los archivos que yo puse aquí en un archivo zip para correr la simulación por Uds. mismos.

En la carpeta sim_reg encontrarán los siguientes archivos (la extensión sv se usa para archivos de System Verilog)

registro.sv - nuestro diseño
tb_reg.sv - testbench
tst.mpf - Archivo de proyecto para Modelsim
wave.do - Definición se señales a visualizar en Modelsim

Una última recomendación, aunque no es obligatorio: Siempre usar el mismo nombre para todo módulo de SystemVerilog y para el archivo en que lo almacenamos, nos ahorraremos muchos dolores de cabeza.



Te interesa la tecnología de FPGAs? Te invito a visitar otro blog mío (en inglés)

Comentarios

Entradas populares de este blog

Introducción a la lógica programable (1) - Compuertas lógicas

Matemática Recreativa: Trepando las dimensiones (primera parte)

Introducción a la lógica de relés