Dominar los bucles For en Verilog: Construir lógica de hardware reutilizable
Un bucle for es el bucle más utilizado en software, pero en Verilog se usa principalmente para replicar lógica de hardware. La idea detrás de un bucle for es iterar un conjunto de declaraciones dadas dentro del bucle mientras la condición dada sea verdadera. Esto es muy similar al bucle while, pero se usa más en un contexto donde hay un iterador disponible y la condición depende del valor de este iterador.
Sintaxis
for (<condición_inicial>; <condición>; <asignación_paso>) begin
// Declaraciones
end
La palabra clave for se usa para especificar este tipo de bucle y tiene tres partes:
- Condición inicial para especificar valores iniciales de señales
- Una comprobación para evaluar si la condición dada es verdadera
- Actualizar la variable de control para la siguiente iteración
La condición inicial y las actualizaciones a la variable de control se incluyen en el bucle for y no es necesario especificarlas por separado a diferencia de un bucle while. Un bucle while es más de propósito general y se usa principalmente solo cuando las declaraciones dadas deben repetirse mientras se cumpla una condición. Sin embargo, el bucle for típicamente tiene un principio y fin definidos controlados por la variable de paso.
Aquí hay un ejemplo simple que ilustra el uso de un bucle for.
module my_design;
integer i;
initial begin
// ¡Tenga en cuenta que el operador ++ no existe en Verilog!
for (i = 0; i < 10; i = i + 1) begin
$display ("Bucle actual #%0d ", i);
end
end
endmodule
ncsim> run Current loop#0 Current loop#1 Current loop#2 Current loop#3 Current loop#4 Current loop#5 Current loop#6 Current loop#7 Current loop#8 Current loop#9 ncsim: *W,RNQUIE: Simulation is complete.
Ejemplo de diseño
Veamos cómo se puede implementar un registro de desplazamiento a la izquierda de 8 bits en Verilog sin un bucle for y luego compararlo con el código usando un bucle for para apreciar la utilidad de una construcción de bucle.
module lshift_reg (
input clk, // Entrada de reloj
input rstn, // Reset activo bajo
input [7:0] load_val, // Valor de carga
input load_en, // Habilitar carga
output reg [7:0] op // Valor de registro de salida
);
// En flanco positivo de reloj, si reset es bajo establecer salida a 0
// Si reset es alto, cargar nuevo valor a op si load_en=1
// Si reset es alto, y load_en=0 desplazar registro a la izquierda
always @ (posedge clk) begin
if (!rstn) begin
op <= 0;
end else begin
if (load_en) begin
op <= load_val;
end else begin
op[0] <= op[7];
op[1] <= op[0];
op[2] <= op[1];
op[3] <= op[2];
op[4] <= op[3];
op[5] <= op[4];
op[6] <= op[5];
op[7] <= op[6];
end
end
end
endmodule
El mismo comportamiento se puede implementar usando un bucle for que reducirá el código y lo hará escalable para diferentes anchos de registro. Si el ancho del registro se hace un parámetro de Verilog, el módulo de diseño se volverá escalable y el mismo parámetro puede usarse dentro del bucle for.
module lshift_reg (
input clk,
input rstn,
input [7:0] load_val,
input load_en,
output reg [7:0] op
);
integer i;
always @ (posedge clk) begin
if (!rstn) begin
op <= 0;
end else begin
// Si load_en es 1, cargar el valor a op
// sino seguir desplazando para cada reloj
if (load_en) begin
op <= load_val;
end else begin
for (i = 0; i < 8; i = i + 1) begin
op[i+1] <= op[i];
end
op[0] <= op[7];
end
end
end
endmodule
Testbench
El código del testbench se muestra a continuación e instancia el diseño.
module tb;
reg clk;
reg rstn;
reg [7:0] load_val;
reg load_en;
wire [7:0] op;
// Configurar reloj DUT
always #10 clk = ~clk;
// Instanciar el diseño
lshift_reg u0 (
.clk(clk),
.rstn(rstn),
.load_val(load_val),
.load_en(load_en),
.op(op)
);
initial begin
// 1. Inicializar variables del testbench
clk <= 0;
rstn <= 0;
load_val <= 8'h01;
load_en <= 0;
// 2. Aplicar reset al diseño
repeat (2) @ (posedge clk);
rstn <= 1;
repeat (5) @ (posedge clk);
// 3. Establecer load_en por 1 clk para que load_val se cargue
load_en <= 1;
repeat(1) @ (posedge clk);
load_en <= 0;
// 4. Dejar que el diseño corra por 20 relojes y luego terminar
repeat (20) @ (posedge clk);
$finish;
end
endmodule
Verilog
- Dominando el bucle for en C#: Sintaxis, flujo y ejemplos prácticos
- Bucles foreach en C#: Itera arrays y colecciones con facilidad
- Dominando los Bucles for en C++: Guía Paso a Paso
- Fundamentos de Verilog: Diseñando tu primera compuerta AND
- Dominar Verilog: Tutorial completo para diseño de circuitos digitales
- Dominar la concatenación en Verilog: Guía práctica
- Comprender las asignaciones en Verilog: tipos, sintaxis y mejores prácticas
- Bloqueante vs. No bloqueante en Verilog: Diferencias clave explicadas
- Dominar las funciones en Verilog para diseño RTL eficiente
- Comprender las Tasks en Verilog: Funciones vs Tasks, sintaxis y uso
- Programa en Java para Identificar Números de Armstrong Usando Bucle For