Manufaturação industrial
Internet das coisas industrial | Materiais industriais | Manutenção e reparo de equipamentos | Programação industrial |
home  MfgRobots >> Manufaturação industrial >  >> Industrial programming >> Verilog

Verilog gerar bloco


A generate block permite multiplicar instâncias de módulo ou realizar instanciação condicional de qualquer módulo. Ele fornece a capacidade de o projeto ser construído com base nos parâmetros Verilog. Essas instruções são particularmente convenientes quando a mesma operação ou instância de módulo precisa ser repetida várias vezes ou se determinado código tiver que ser incluído condicionalmente com base em determinados parâmetros Verilog.

Um generate o bloco não pode conter porta, parâmetro, specparam declarações ou specify blocos. No entanto, outros itens de módulo e outros blocos de geração são permitidos. Todas as instanciações geradas são codificadas dentro de um module e entre as palavras-chave generate e endgenerate .

As instanciações geradas podem ter módulos, atribuições contínuas, always ou initial blocos e primitivos definidos pelo usuário. Existem dois tipos de construções de geração - loops e condicionais.

Gerar loop for


Um meio somador será instanciado N vezes em outro módulo de design de nível superior chamado my_design usando um generate para construção de loop. A variável de loop deve ser declarada usando a palavra-chave genvar que informa à ferramenta que esta variável deve ser usada especificamente durante a elaboração do bloco de geração.
  
  
// 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 teste


O parâmetro testbench é usado para controlar o número de instâncias de meio somador no projeto. Quando N for 2, my_design terá duas instâncias de meio somador.
  
  
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] e b[0] fornecem a soma de saída[0] e cout[0] enquanto a[1] e b[1] fornecem a soma de saída[1] e cout[1].
Registro de simulação
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


Veja que o RTL elaborado realmente tem duas instâncias de meio somador geradas pelo generate quadra.

Gerar se


Abaixo está um exemplo usando um if else dentro de um generate construir para selecionar entre duas implementações de multiplexadores diferentes. O primeiro design usa um assign para implementar um mux enquanto o segundo design usa um case declaração. Um parâmetro chamado USE_CASE é definido no módulo de design de nível superior para selecionar entre as duas opções.
  
  
// 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 teste


O Testbench instancia o módulo de nível superior my_design e define o parâmetro USE_CASE como 1 para que instancia o design usando case declaração.
  
  
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

  

Quando o parâmetro USE_CASE é 1, pode-se ver no log de simulação que o projeto do multiplexador usando case declaração é instanciada. E quando USE_CASE é zero, o projeto do multiplexador usando assign declaração é instanciada. Isso é visível na instrução de exibição que é impressa no log de simulação.
Registro de simulação
// 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.

Gerar caso


Um caso de geração permite que módulos, blocos iniciais e sempre sejam instanciados em outro módulo com base em um case expressão para selecionar uma das muitas opções.
  
  
// 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 teste

  
  
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

  

Observe que, como um meio somador é instanciado, cin não tem nenhum efeito nas saídas soma e cout.
Registro de simulação
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 Verilog
  2. Concatenação Verilog
  3. Verilog - Em uma casca de noz
  4. Atribuições Verilog
  5. Verilog Blocking &Non-Blocking
  6. Funções Verilog
  7. Tarefa Verilog
  8. Gerador de Relógio Verilog
  9. Funções matemáticas Verilog
  10. Formato de hora Verilog