¿Cómo se implementan las declaraciones Verilog "siempre" en el hardware?

8

La declaración Verilog always , a saber

always @(/* condition */)
    /* block of code */

ejecuta el block of code siempre que se cumpla condition . ¿Cómo se implementa dicho bloque always en hardware?

    
pregunta Randomblue

3 respuestas

15

Primero, tenga en cuenta que no todos los diseños de Verilog son sintetizables. Por lo general, solo se puede utilizar un subconjunto de construcciones muy específico en un diseño que se realizará en hardware.

Una restricción importante que aparece es que cada variable reg solo se puede asignar en como máximo una declaración always . En otras palabras, reg s tiene afinidad con los bloques always .

Generalmente se pueden usar los siguientes tipos de bloques always .

always @(*) begin
    // combinational
end

always @(posedge clk) begin
    // sequential
end

En el primer caso, el * indica que el bloque debe ejecutarse siempre que cambie alguna señal utilizada en el bloque o, de manera equivalente, que el bloque se ejecute continuamente. Por lo tanto, reg s que tienen afinidad con los bloques combinacionales always se implementan como señales calculadas a partir de otras señales usando lógica combinacional, es decir, puertas.

Los registros que tienen afinidad con los bloques always del último tipo, por otro lado, son salidas de flip-flops D que están sincronizados en el borde ascendente de clk (borde descendente si se usa negedge ) . Las entradas a los flip-flops son, nuevamente, computadas con lógica combinacional de otras señales.

Considere el siguiente ejemplo, un tanto artificial.

reg out, out_n;
always @(*) begin
    out_n = !out;
end
always @(posedge clk) begin
    out <= !out;
end

Aquí, out_n está asociado con el primer bloque always , out con el segundo. out_n se implementará con una única puerta NOT que manejará out_n y se manejará desde out (tenga en cuenta que es una lógica combinacional pura). Por otro lado, out será impulsado por un flip-flop cronometrado desde clk . La entrada al flip-flop será nuevamente calculada por una puerta NOT desde out (que es impulsada por el flip-flop mencionado anteriormente). La optimización de los sintetizadores combinará las dos puertas NO y utilizará una puerta NO y un flip-flop.

Dependiendo del hardware que tenga disponible, se pueden usar otros tipos de construcciones. Por ejemplo, si los flip-flops tienen restablecimientos asíncronos, la siguiente construcción también es sintetizable.

always @(posedge clk or posedge rst) begin
    if (rst)
        // reset
    else
        // sequential
end
    
respondido por el avakar
2

Un bloque always se usa comúnmente para describir un flip-flop, un pestillo o un multiplexor. El código se implementaría con un flip-flop, un pestillo o un multiplexor.

En un FPGA, un flip-flop y un pestillo generalmente son solo dos configuraciones diferentes de un dispositivo de registro de propósito más general. Un multiplexor se construiría a partir de uno o más elementos lógicos de propósito general (LUT).

En general, hay dos formas de realizar el diseño con Verilog:

  1. Visualice la lógica que desea en términos de puertas y registros, luego descubra cómo describirla en Verilog. Las guías de síntesis de los proveedores de FPGA o los proveedores de herramientas de síntesis ofrecen una placa de calderas para las estructuras más comunes con las que podría querer trabajar.

  2. Simplemente escribe Verilog y no te preocupes por el aspecto del hardware subyacente. Sin embargo, incluso si haces esto, debes saber qué es y qué no se puede sintetizar. Nuevamente, buscará la placa de calderas provista por su proveedor de herramientas y la adaptará a su aplicación.

EDIT

La respuesta de Avakar es mucho mejor para tu pregunta, pero esto provocó una interesante discusión sobre las diferencias entre Xilinx y Altera, por lo que no la eliminaré.

    
respondido por el The Photon
0

Como se ha dicho, no todos los bloques siempre son sintetizables. También hay algunos bloques que las herramientas de síntesis aceptarán pero que producirán resultados que difieren de lo que producirá un simulador.

Primero de la lista de sensibilidad. La regla habitual es que debe contener solo construcciones de detección de bordes (y generalmente hay una selección limitada de combinaciones posibles) o debe contener (posiblemente a través del uso de * o systemverilog's always_comb) cada señal utilizada como entrada al bloque. Llamamos a lo primero bloque combinatorio y lo segundo a secuencia o bloque. Por lo general, si solo incluye un subconjunto de entradas en una herramienta de síntesis de bloques combinatoria, simplemente lo ignorará y actuará como si se hubiera especificado la lista completa (creando desajustes de simulación / síntesis)

Bloqueo segundo vs asignaciones noblocking. En un bloque combinatorio, la diferencia no importa mucho, pero en un bloque secuencial es muy importante.

En un bloque secuencial, las asignaciones sin bloqueo modelan un registro de manera bastante directa, mientras que el bloqueo de las asignaciones modela las variables (lo que puede o no implicar registros según el orden de configuración y lectura). Como regla general, un conjunto "reg" que utiliza las configuraciones de bloqueo en un bloque secuencial solo debe leerse en el mismo bloque, y las evaluaciones de bloqueo y sin bloqueo no deben mezclarse en el mismo "reg".

Es probable que la mezcla de asignaciones de bloqueo y no bloqueo en el mismo elemento cause fallas de síntesis. Hacer un análisis de bloqueo en un bloque y leerlo en otro es probable que provoque desajustes de simulación / síntesis (y posiblemente incluso desajustes entre diferentes ejecuciones de simulación).

Ahora tenemos las reglas básicas de la manera en que podemos considerar cómo el compilador convierte el código en lógica.

El primer paso es desenrollar todos los bucles. Esto significa que los bucles deben tener un recuento de iteraciones máximo que se puede determinar en el momento de la síntesis o se producirá un error de síntesis.

Luego, la herramienta puede analizar el flujo de control del bloque y convertirlo en un flujo de datos. Cada variable se convierte en una o más señales. Cada sentencia if o construcción similar se convierte en uno o más multiplexores que seleccionan qué conjunto de resultados se utilizarán realmente.

Es probable que la herramienta intente y aplique algunas opciones.

En quartus, puedes ver los resultados de este proceso después de construir tu proyecto en "herramientas- > netlist viewers- > rtl viewer".

Después de generar esta representación estructural en términos de elementos lógicos abstractos, la herramienta pasará a mapear esos elementos abstractos en los recursos que realmente tiene el chip.

    
respondido por el Peter Green

Lea otras preguntas en las etiquetas