Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Industrial programming >> Verilog

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:

  1. Condición inicial para especificar valores iniciales de señales
  2. Una comprobación para evaluar si la condición dada es verdadera
  3. 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

  1. Dominando el bucle for en C#: Sintaxis, flujo y ejemplos prácticos
  2. Bucles foreach en C#: Itera arrays y colecciones con facilidad
  3. Dominando los Bucles for en C++: Guía Paso a Paso
  4. Fundamentos de Verilog: Diseñando tu primera compuerta AND
  5. Dominar Verilog: Tutorial completo para diseño de circuitos digitales
  6. Dominar la concatenación en Verilog: Guía práctica
  7. Comprender las asignaciones en Verilog: tipos, sintaxis y mejores prácticas
  8. Bloqueante vs. No bloqueante en Verilog: Diferencias clave explicadas
  9. Dominar las funciones en Verilog para diseño RTL eficiente
  10. Comprender las Tasks en Verilog: Funciones vs Tasks, sintaxis y uso
  11. Programa en Java para Identificar Números de Armstrong Usando Bucle For