Menu

Loops for en Verilog: desenrollados en tiempo de compilación

Cómo los loops for de Verilog difieren de sus primos del software - los desenrolla el sintetizador en hardware paralelo, no se ejecutan iterativamente en runtime.

Esta página incluye editores ejecutables: edita, ejecuta y ve el resultado al instante.

El parecido al software

El loop for de Verilog es una copia del de C:

for (i = 0; i < 8; i = i + 1) begin
    // body
end

Las mismas tres partes: inicializador, condición, incremento. El cuerpo vuelve a correr mientras la condición se mantiene.

En un testbench, esto se comporta exactamente como esperarías del software. El simulador recorre cada iteración por turno:

Cuatro iteraciones, cuatro líneas de salida. Sin sorpresas.

La sorpresa viene cuando metes un loop for dentro de código sintetizable.

El desenrollado

Un loop for en un bloque always sintetizable no se convierte en un loop en runtime en el hardware. El sintetizador lo desenrolla en tiempo de elaboración - lo expande en N copias del cuerpo, donde N es el número de iteraciones:

Eso parece un loop. En simulación, el simulador sí recorre ocho iteraciones. En síntesis, el loop se desenrolla en ocho comprobaciones paralelas de data[0] hasta data[7], todas ocurriendo al mismo tiempo. El sintetizador ve:

count = 0;
if (data[0]) count = count + 1;
if (data[1]) count = count + 1;
if (data[2]) count = count + 1;
...
if (data[7]) count = count + 1;

…y luego convierte la secuencia en un árbol de sumadores. El comportamiento en runtime es "mira los 8 bits a la vez y cuenta cuántos son 1", en un único barrido combinacional.

La implicación: un loop for en Verilog sintetizable no es gratis. Un loop de 64 iteraciones se convierte en 64 copias del cuerpo en hardware. Si el cuerpo es complejo, acabas de construir un bloque combinacional grande. Usa loops cuando N es pequeño (un puñado o unas decenas). Para conteos mayores, normalmente quieres un contador sincronizado y una máquina de estados.

Se requieren límites constantes

El sintetizador solo puede desenrollar el loop si conoce N en tiempo de elaboración. Eso significa que los límites del loop deben ser constantes:

// Works - bound is constant
for (i = 0; i < 8; i = i + 1) ...

// Works - bound is a parameter
for (i = 0; i < WIDTH; i = i + 1) ...

// Doesn't synthesize - bound depends on a runtime signal
for (i = 0; i < dynamic_count; i = i + 1) ...

La última forma puede aún funcionar en simulación, pero el sintetizador la rechazará. Si realmente necesitas un loop con cuenta en runtime, lo construyes con una máquina de estados sincronizada y un registro contador - el hardware no tiene loops de número variable de pasadas como tiene el software.

generate for vs for procedural

Una construcción separada pero relacionada es generate for, que usa un genvar y vive fuera de los bloques always:

genvar i;
generate
    for (i = 0; i < 8; i = i + 1) begin : g
        bit_inverter inv(.x(in[i]), .y(out[i]));
    end
endgenerate

Eso crea 8 instancias de bit_inverter (cubierto en Module Instantiation). Es estructural - estás diciendo "haz 8 copias de este submódulo" - no comportamental.

Distinción rápida:

  • for procedural (dentro de always) - desenrolla sentencias dentro de un único bloque conductual.
  • for de generate (fuera de always) - replica construcciones estructurales enteras: instancias, sentencias assign, bloques con nombre.

Usa el que coincida con lo que estás replicando.

Cuándo brilla for: operaciones vectoriales

Los loops están en su mejor versión cuando estás haciendo la misma operación a cada bit de un vector. Conteo de población, paridad, inversión de bytes, generación de tablas de lookup:

32 iteraciones, cada una haciendo una asignación de un bit - mucho más legible que escribir 32 asignaciones a mano. El sintetizador desenrolla limpiamente.

while, repeat, forever

Más allá de for, Verilog tiene tres construcciones de loop más - mayormente para testbenches:

// Run until a condition fails
while (~done) begin
    @(posedge clk);
    cycles = cycles + 1;
end

// Run N times - simpler than for when you don't need a counter
repeat (8) @(posedge clk);

// Run forever - clock generators, monitoring loops
always #5 clk = ~clk;
forever begin
    @(posedge clk);
    $display("count=%0d", count);
end

while, repeat y forever son sintetizables solo en casos estrechos (notablemente repeat con un conteo constante y un cuerpo sincronizado). En testbenches son herramientas útiles; en RTL sintetizable prefiere un for contado más una máquina de estados explícita.

for procedural en testbenches

En un testbench, los loops for se comportan como en software. Úsalos libremente:

Los loops anidados barren cada combinación de dos entradas de 2 bits. El simulador ejecuta las iteraciones secuencialmente. Sin preocupaciones de desenrollado - los testbenches no sintetizan.

Errores comunes

Usar un loop for en código sintetizable con un límite no constante. El sintetizador lo rechazará. Si el límite es runtime, construye un contador y una máquina de estados.

Olvidar que el cuerpo del loop se convierte en hardware paralelo. Un loop de 64 iteraciones con un multiplicador en el cuerpo es 64 multiplicadores paralelos - probablemente no lo que quieres. Para datapaths anchos, construye un único multiplicador y aliméntalo secuencialmente.

Mezclar integer i y un reg llamado i. Los dos son ámbitos distintos; el integer gana dentro del loop. Elige nombres claros para evitar la confusión.

Qué viene a continuación

Ya tienes todas las construcciones procedurales que ofrece Verilog. El siguiente capítulo lo junta todo en los patrones que los diseñadores digitales realmente envían: Clocked Logic - flip-flops, registros y pipelines - y Finite State Machines - el modismo estándar para cualquier controlador con varios modos de operación.

Preguntas frecuentes

¿Cómo funcionan los loops for en Verilog?

Sintácticamente parecen los de C: for (i = 0; i < N; i = i + 1) statement;. Pero para código sintetizable, el loop se desenrolla en tiempo de elaboración - el sintetizador lo expande en N copias del cuerpo. No hay contador de loop en runtime y no hay loop en el hardware. Para testbenches, los loops for se comportan como sus primos del software porque el simulador puede recorrerlos secuencialmente.

¿Es sintetizable un loop for en Verilog?

Sí, pero solo cuando los límites del loop son constantes conocidas en tiempo de elaboración. El sintetizador desenrolla el loop en N copias paralelas del cuerpo. Si los límites dependen de una señal en runtime, el loop no es sintetizable - tienes que convertirlo en un diseño secuencial sincronizado.

¿Cuál es la diferencia entre for y generate for en Verilog?

Un loop for dentro de un bloque always es una construcción procedural que sintetiza desenrollándose. Un loop generate for (con genvar) es una construcción explícita en tiempo de elaboración que crea hardware estructural - varias instancias de módulo, varios wires, varias sentencias assign. Usa for dentro de bloques procedurales; usa generate for fuera de ellos para replicar estructura.

¿Tiene Verilog un loop while?

Sí - while (condition) statement;. Es sintetizable solo cuando el sintetizador puede probar que el loop termina con un número acotado de iteraciones. En la práctica eso es raro, así que while aparece mayormente en testbenches y código solo de simulación. Para iteración sintetizable, usa un loop for contado.

Coddy programming languages illustration

Aprende a programar con Coddy

COMENZAR