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

Verilog generar bloque

Un generate block permite multiplicar instancias de módulos o realizar una instanciación condicional de cualquier módulo. Proporciona la capacidad de que el diseño se construya en función de los parámetros de Verilog. Estas declaraciones son particularmente convenientes cuando la misma operación o instancia de módulo debe repetirse varias veces o si cierto código debe incluirse condicionalmente en función de determinados parámetros de Verilog.

Un generate el bloque no puede contener puerto, parámetro, specparam declaraciones o specify bloques Sin embargo, se permiten otros elementos del módulo y otros bloques de generación. Todas las instancias generadas están codificadas dentro de un module y entre las palabras clave generate y endgenerate .

Las instancias generadas pueden tener módulos, asignaciones continuas, always o initial bloques y primitivas definidas por el usuario. Hay dos tipos de construcciones de generación:bucles y condicionales.

Generar bucle for

Un medio sumador será instanciado N veces en otro módulo de diseño de nivel superior llamado my_design usando un generate para construcción de bucle. La variable de bucle debe declararse con la palabra clave genvar que le dice a la herramienta que esta variable se usará específicamente durante la elaboración del bloque de generación.

  
  
// Design for a half-adder
module ha ( input   a, b,
            output  sum, cout);
 
  assign sum  = a ^ b;
  assign cout = a & b;
endmodule

// A top level design that contains N instances of half adder
module my_design 
	#(parameter N=4) 
		(	input [N-1:0] a, b,
			output [N-1:0] sum, cout);
			
	// Declare a temporary loop variable to be used during
	// generation and won't be available during simulation
	genvar i;
	
	// Generate for loop to instantiate N times
	generate 
		for (i = 0; i < N; i = i + 1) begin
          ha u0 (a[i], b[i], sum[i], cout[i]);
		end
	endgenerate
endmodule

  

Banco de pruebas

El parámetro testbench se usa para controlar el número de instancias de medio sumador en el diseño. Cuando N es 2, my_design tendrá dos instancias de medio sumador.

  
  
module tb;
	parameter N = 2;
  reg  [N-1:0] a, b;
  wire [N-1:0] sum, cout;
  
  // Instantiate top level design with N=2 so that it will have 2
  // separate instances of half adders and both are given two separate
  // inputs
  my_design #(.N(N)) md( .a(a), .b(b), .sum(sum), .cout(cout));
  
  initial begin
    a <= 0;
    b <= 0;
    
    $monitor ("a=0x%0h b=0x%0h sum=0x%0h cout=0x%0h", a, b, sum, cout);
    
    #10 a <= 'h2;
    		b <= 'h3;
    #20 b <= 'h4;
    #10 a <= 'h5;
  end
endmodule

  

a[0] y b[0] dan la salida sum[0] y cout[0] mientras que a[1] y b[1] dan la salida sum[1] y cout[1].

Registro de simulación
ncsim> run
a=0x0 b=0x0 sum=0x0 cout=0x0
a=0x2 b=0x3 sum=0x1 cout=0x2
a=0x2 b=0x0 sum=0x2 cout=0x0
a=0x1 b=0x0 sum=0x1 cout=0x0
ncsim: *W,RNQUIE: Simulation is complete.
ncsim> exit

Vea que RTL elaborado de hecho tiene dos instancias de medio sumador generadas por el generate bloquear.

Generar si

A continuación se muestra un ejemplo usando un if else dentro de un generate construir para seleccionar entre dos implementaciones de multiplexor diferentes. El primer diseño usa un assign declaración para implementar un mux mientras que el segundo diseño usa un case declaración. Un parámetro llamado USE_CASE se define en el módulo de diseño de nivel superior para seleccionar entre las dos opciones.

  
  
// Design #1: Multiplexer design uses an "assign" statement to assign 
// out signal 
module mux_assign ( input a, b, sel,
                   output out);
  assign out = sel ? a : b;
  
  // The initial display statement is used so that 
  // we know which design got instantiated from simulation
  // logs  
  initial
  	$display ("mux_assign is instantiated");
endmodule

// Design #2: Multiplexer design uses a "case" statement to drive
// out signal
module mux_case (input a, b, sel,
                 output reg out);
  always @ (a or b or sel) begin
  	case (sel)
    	0 : out = a;
   	 	1 : out = b;
  	endcase
  end
  
  // The initial display statement is used so that 
  // we know which design got instantiated from simulation
  // logs
  initial 
    $display ("mux_case is instantiated");
endmodule

// Top Level Design: Use a parameter to choose either one
module my_design (	input a, b, sel,
         			output out);
  parameter USE_CASE = 0;
  
  // Use a "generate" block to instantiate either mux_case
  // or mux_assign using an if else construct with generate
  generate
  	if (USE_CASE) 
      mux_case mc (.a(a), .b(b), .sel(sel), .out(out));
    else
      mux_assign ma (.a(a), .b(b), .sel(sel), .out(out));
  endgenerate
    
endmodule

  

Banco de pruebas

Testbench instancia el módulo de nivel superior my_design y establece el parámetro USE_CASE en 1 para que instancia el diseño usando case declaración.

  
  
module tb;
	// Declare testbench variables
  reg a, b, sel;
  wire out;
  integer i;
  
  // Instantiate top level design and set USE_CASE parameter to 1 so that
  // the design using case statement is instantiated
  my_design #(.USE_CASE(1)) u0 ( .a(a), .b(b), .sel(sel), .out(out));
  
  initial begin
  	// Initialize testbench variables
  	a <= 0;
    b <= 0;
    sel <= 0;
    
    // Assign random values to DUT inputs with some delay
    for (i = 0; i < 5; i = i + 1) begin
      #10 a <= $random;
      	  b <= $random;
          sel <= $random;
      $display ("i=%0d a=0x%0h b=0x%0h sel=0x%0h out=0x%0h", i, a, b, sel, out);
    end
  end
endmodule

  

Cuando el parámetro USE_CASE es 1, se puede ver en el registro de simulación que el diseño del multiplexor usa case se instancia la declaración. Y cuando USE_CASE es cero, el diseño del multiplexor usa assign se instancia la declaración. Esto es visible en la declaración de visualización que se imprime en el registro de simulación.

Registro de simulación
// When USE_CASE = 1
ncsim> run
mux_case is instantiated
i=0 a=0x0 b=0x0 sel=0x0 out=0x0
i=1 a=0x0 b=0x1 sel=0x1 out=0x1
i=2 a=0x1 b=0x1 sel=0x1 out=0x1
i=3 a=0x1 b=0x0 sel=0x1 out=0x0
i=4 a=0x1 b=0x0 sel=0x1 out=0x0
ncsim: *W,RNQUIE: Simulation is complete.

// When USE_CASE = 0
ncsim> run
mux_assign is instantiated
i=0 a=0x0 b=0x0 sel=0x0 out=0x0
i=1 a=0x0 b=0x1 sel=0x1 out=0x0
i=2 a=0x1 b=0x1 sel=0x1 out=0x1
i=3 a=0x1 b=0x0 sel=0x1 out=0x1
i=4 a=0x1 b=0x0 sel=0x1 out=0x1
ncsim: *W,RNQUIE: Simulation is complete.

Generar caso

Un caso de generación permite instanciar módulos, bloques iniciales y siempre en otro módulo basado en un case expresión para seleccionar una de las muchas opciones.

  
  
// Design #1: Half adder
module ha (input a, b,
           output reg sum, cout);
  always @ (a or b)
  {cout, sum} = a + b;
  
  initial
    $display ("Half adder instantiation");
endmodule

// Design #2: Full adder
module fa (input a, b, cin,
           output reg sum, cout);
  always @ (a or b or cin)
  {cout, sum} = a + b + cin;
  
    initial
      $display ("Full adder instantiation");
endmodule

// Top level design: Choose between half adder and full adder
module my_adder (input a, b, cin,
                 output sum, cout);
  parameter ADDER_TYPE = 1;
  
  generate
    case(ADDER_TYPE)
      0 : ha u0 (.a(a), .b(b), .sum(sum), .cout(cout));
      1 : fa u1 (.a(a), .b(b), .cin(cin), .sum(sum), .cout(cout));
    endcase
  endgenerate
endmodule

  

Banco de pruebas

  
  
module tb;
  reg a, b, cin;
  wire sum, cout;
  
  my_adder #(.ADDER_TYPE(0)) u0 (.a(a), .b(b), .cin(cin), .sum(sum), .cout(cout));
  
  initial begin
    a <= 0;
    b <= 0;
    cin <= 0;
    
    $monitor("a=0x%0h b=0x%0h cin=0x%0h cout=0%0h sum=0x%0h",
             a, b, cin, cout, sum);
    
    for (int i = 0; i < 5; i = i + 1) begin
      #10 a <= $random;
      b <= $random;
      cin <= $random;
    end
  end
endmodule

  

Tenga en cuenta que debido a que se instancia un medio sumador, cin no tiene ningún efecto en las salidas sum y cout.

Registro de simulación
ncsim> run
Half adder instantiation
a=0x0 b=0x0 cin=0x0 cout=00 sum=0x0
a=0x0 b=0x1 cin=0x1 cout=00 sum=0x1
a=0x1 b=0x1 cin=0x1 cout=01 sum=0x0
a=0x1 b=0x0 cin=0x1 cout=00 sum=0x1
ncsim: *W,RNQUIE: Simulation is complete.


Verilog

  1. Tutorial de Verilog
  2. Concatenación Verilog
  3. Verilog - En pocas palabras
  4. Asignaciones de Verilog
  5. Bloqueo y no bloqueo de Verilog
  6. Funciones de Verilog
  7. Tarea Verilog
  8. Generador de reloj Verilog
  9. Funciones matemáticas de Verilog
  10. Formato de hora de Verilog
  11. Alcance de la escala de tiempo de Verilog