Apuntes sobre Verilog

Tema 2. Formas de Describir Circuitos

18 de diciembre de 2021


2. Formas de Modelar Circuitos

Hay varias maneras de implementar hardware en Verilog:


2.1 Describiendo el circuito a nivel de puerta y su estructura, gate level.

2.2 Describiendo el flujo de datos, dataflow modeling.

2.3 Describiendo el comportamiento del circuito, behavioral modeling

2.4 Describiendo la estructura jerárquica, structural modeling


El diseño de módulos también puede hacerse mezclando los estilos anteriores. Por ejemplo otra forma de describir circuitos es Register Transfer Level o RTL, que es una combinación de dataflow & behavioral modeling y determina el flujo de datos a través de los circuitos lógicos.

2.1. Gate level modeling


Para circuitos donde el número de puertas lógicas no es muy grande, el modelado a nivel de puertas es una opción de diseño muy recomendable. Esta forma de modelar circuitos utiliza puertas lógicas básicas (NAND, OR, NOT...) y permite que un diseñador con unos conocimientos básicos pueda instanciar y conectar dichas puertas individualmente. 


Un ejemplo de modelado de un circuito con puertas lógicas lo tenemos en el multiplexor 2:1 de la imagen siguiente. Declaramos las entradas, salidas y una lista opcional de posibles cables que unen internamente las E/S tal y como lo haríamos si implementásemos el circuito en una protoboard.

module multiplexor_2_1 ( input in1, in2, sel, output out);


wire w1, w2, w3;


not NOT1 (w2, sel);

and AND1 (w1, in1, w2);

and AND2 (w3, sel, in2);

or OR1 (out, w1, w3); 

endmodule 

Cada una de las palabras clave not and or se llaman primitivas. Son puertas lógicas predefinidas incluidas en la librería de Verilog . En cada una de las cuatro líneas del código anterior estamos instanciado puertas lógicas. Al instanciar se crea una jerarquía donde el módulo principal (multiplexor_2_1) contiene otros submódulos (las puertas lógicas not and or).

2.2 Dataflow modeling


Dataflow hace referencia al estilo de describir un circuito en términos de cómo se procesan los datos y cómo fluyen las señales a través del hardware.


Esta forma de describir circuitos se hace mediante asignaciones continuas (continuous assignments). La palabra clave assign indica una asignación continua en el sentido de que gobierna constantemente la relación entre las entradas y las salidas; cuando una entrada cambia, la salida cambia inmediatamente.


No hay una señal de reloj que indique cuando tiene lugar una operación, el circuito funciona en tiempo real, de igual forma que la salida de una puerta lógica siempre está determinada en todo momento por el valor de sus entradas. 


Las declaraciones assign se colocan por lo general a continuación de la declaración de E/S y se utilizan principalmente para describir circuitos combinacionales mediante su comportamiento (behavioral modeling), aunque también se admite en circuitos secuenciales.


Las variables a la izquierda del signo = deben ser obligatoriamente tipo wire mientras que a la derecha del = pueden ser tipo wire, reg o una constante. Un módulo puede contener cualquier número de declaraciones assign.


Veamos algunos ejemplos de asignación continua.


Ejemplo 1. Asignación continua con operadores lógicos


El siguiente módulo describe una puerta AND:

module AND (input in1, in2, output out);


 assign out = in1 & in2;


endmodule

Ejemplo 2. Multiplexor 2:1 descrito mediante su comportamiento.

module multiplexor_2_1 (input [1:0] in, input sel, output out);


assign out = in [sel];


endmodule

Ejemplo 3. Multiplexor 2:1 asignación continua con operador condicional

module multiplexor_2_1 (input in1, in2, sel, output out);


assign out = sel ? in1 : in2;


endmodule


Un operador condicional se declara como sigue: 


conditional_expression ? true_expression : false_expression;

assign z = (b>c) ? x : y;

si b>c es true entonces asignamos a z el valor de x es decir: z = x

si b>c es false entonces asignamos a z el valor de y es decir: z = y

2.3 Behavioral modeling


El modelado de circuitos mediante el comportamiento describe qué hace el circuito; se especifican las entradas, salidas y la relación entre ellas,  ignorando la estructura interna del circuito y su implementación física. Para describir un circuito mediante su comportamiento se utilizan las declaraciones initial y always.


El estilo de descripción de un circuito mediante su comportamiento, utiliza asignaciones de procedimiento -procedural assignment- para modelar las asignaciones de señales basadas en un evento o transición de una señal.  Las declaraciones procedurales sólo pueden hacerse en los bloques de procedimiento always e initial, es decir, las procedural assignments  se hacen dentro de un procedural block.


La declaración initial se utiliza en simulación y sólo se ejecuta una vez.  


Un bloque always ejecuta constantemente las declaraciones que contiene. Un módulo puede contener varias declaraciones initial  y always


Las declaraciones procedurales se basan en eventos, es decir, la asignación se hace cuando se cumple alguna de las condiciones descritas en la lista de sensibilidades de la declaración always por ejemplo:

always @ (posedge clk) // con cada flanco positivo de reloj

always @ (!reset) // cada vez que reset = 0

always @ (in1, in2, sel) // cada vez que haya un cambio en las entradas


Dentro de un bloque always sólo se pueden hacer asignaciones a variables tipo reg

Estas asignaciones pueden ser blocking cuando el circuito es combinacional (se denotan por el signo = )  o non blocking (se denotan por el signo <= ) para circuitos secuenciales; circuitos síncronos con señal de reloj. No se deben mezclar asignaciones blocking y non blocking dentro del mismo bloque.


Algunas de las declaraciones que se utilizan dentro de un bloque always son: 



Veamos algunos ejemplos.


Ejemplo 1. Modelado de un multiplexor 2:1 mediante su comportamiento con estructura case


Definimos las entradas y salidas y cómo se comportan, ignorando cómo se implementa el circuito físicamente dentro de la FPGA.

module multiplexor_2_1 (input in1, in2, sel, output reg out);


always @ (in1, in2, sel)

 case (sel)

  1'b0: out = in1;

  1'b1: out = in2;

 endcase


endmodule


· En una estructura case no hay prioridades a la hora de evaluar la variable sensitiva; todas las condiciones se evalúan a la vez.

Ejemplo 2. Modelado de un multiplexor 2:1 mediante su comportamiento con estructura if-then-else


Al igual que en la estructura case, las salidas se declaran tipo reg para que conserven su valor.


module multiplexor_2_1 (input in1, in2, sel, output reg out);


always @ (in1, in2, sel)

 if (sel == 1'b0)

  out = in1;

else if (sel == 1'b1)

  out = in2;


endmodule


En una estructura if-then-else hay prioridad; las condiciones se evalúan de arriba hacia abajo.

2.4 Structural modeling


Verilog soporta una estructura de descripción de hardware jerárquica permitiendo que unos módulos sean embebidos dentro de otros módulos. El término structural modeling, hace referencia a la posibilidad de instanciar otros módulos para conseguir la funcionalidad deseada.


Esto se llama jerarquía y es una buena práctica de diseño porque permite la partición del diseño en circuitos pequeños, más sencillos de implementar.


Un diseño puramente estructural no contendrá ningún módulo en el que se hagan asignaciones de señales, sino que sólo contendrá la instanciación e interconexiones de otros submódulos. 


El término instanciar se refiere a la inclusión de un módulo de nivel inferior dentro de otro módulo de nivel superior. Los módulos de nivel superior crean instancias de módulos de nivel inferior y se conectan con cables a los puertos de entrada, salida y bidireccionales.


Cualquiera que sea el estilo que hemos utilizado para modelar un circuito lógico, ya sea gate level, dataflow o behavioral, es susceptible de poder instanciarse y cuando lo hacemos estamos definiendo la estructura del circuito y estableciendo una jerarquía.


Cada módulo en Verilog es un módulo de nivel superior o un módulo instanciado. Hay un único módulo de nivel superior que no se instancia en ninguna otra parte del diseño.


Existen dos técnicas para interconectar los puertos de los módulos que se desean instanciar: mapeo explícito y mapeo posicional. El circuito de la figura representa un ejemplo de mapeo de puertos explícito. Más detalles aquí.

Esquema resumen