Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Industrial programming >> Verilog

Verilog blok genereren

Een generate block maakt het mogelijk om module-instanties te vermenigvuldigen of voorwaardelijke instantie van een module uit te voeren. Het biedt de mogelijkheid om het ontwerp te bouwen op basis van Verilog-parameters. Deze instructies zijn met name handig wanneer dezelfde bewerking of module-instantie meerdere keren moet worden herhaald of als bepaalde code voorwaardelijk moet worden opgenomen op basis van bepaalde Verilog-parameters.

Een generate blok mag geen poort, parameter, specparam bevatten aangiften of specify blokken. Andere module-items en andere genererende blokken zijn echter toegestaan. Alle genereren instantiaties zijn gecodeerd binnen een module en tussen de trefwoorden generate en endgenerate .

Gegenereerde instantiaties kunnen modules, doorlopende toewijzingen, always . hebben of initial blokken en door de gebruiker gedefinieerde primitieven. Er zijn twee soorten genereer-constructies:lussen en voorwaardelijke.

  • Genereer for loop
  • Genereer indien anders
  • Case genereren

Genereer for loop

Een halve opteller wordt N keer geïnstantieerd in een andere ontwerpmodule op het hoogste niveau, my_design genaamd, met een generate voor lusconstructie. De lusvariabele moet worden gedeclareerd met het trefwoord genvar die de tool vertelt dat deze variabele specifiek moet worden gebruikt tijdens het uitwerken van het genereerblok.

  
  
// 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

  

Testbank

De testbench-parameter wordt gebruikt om het aantal halve optellerinstanties in het ontwerp te regelen. Als N 2 is, heeft my_design twee gevallen van halve opteller.

  
  
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] en b[0] geven de output sum[0] en cout[0] terwijl a[1] en b[1] de output sum[1] en cout[1] geven.

Simulatielogboek
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

Zie dat uitgewerkte RTL inderdaad twee halve adder-instanties heeft die worden gegenereerd door de generate blok.

Genereren als

Hieronder wordt een voorbeeld weergegeven met een if else in een generate constructie om te kiezen tussen twee verschillende multiplexerimplementaties. Het eerste ontwerp gebruikt een assign statement om een ​​mux te implementeren terwijl het tweede ontwerp een case . gebruikt uitspraak. Een parameter genaamd USE_CASE is gedefinieerd in de ontwerpmodule op het hoogste niveau om tussen de twee keuzes te kiezen.

  
  
// 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

  

Testbank

Testbench maakt de module op het hoogste niveau my_design en stelt de parameter USE_CASE in op 1 zodat het ontwerp wordt geïnstantieerd met behulp van case verklaring.

  
  
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

  

Wanneer de parameter USE_CASE 1 is, kan uit het simulatielogboek worden gezien dat de multiplexer ontwerpt met behulp van case verklaring wordt geconcretiseerd. En wanneer USE_CASE nul is, ontwerpt de multiplexer met assign verklaring wordt geconcretiseerd. Dit is te zien aan de weergaveverklaring die wordt afgedrukt in het simulatielogboek.

Simulatielogboek
// 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.

Case genereren

Met een genereercase kunnen modules, initiële en altijd blokken worden geïnstantieerd in een andere module op basis van een case expressie om een ​​van de vele keuzes te selecteren.

  
  
// 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

  

Testbank

  
  
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

  

Merk op dat omdat een halve opteller is geïnstantieerd, cin geen enkel effect heeft op de outputs som en cout.

Simulatielogboek
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. Verilog-zelfstudie
  2. Verilog-aaneenschakeling
  3. Verilog - In een notendop
  4. Verilog-opdrachten
  5. Verilog blokkeren en niet-blokkeren
  6. Verilog-functies
  7. Verilog-taak
  8. Verilog-klokgenerator
  9. Verilog wiskundige functies
  10. Verilog Tijdnotatie
  11. Verilog Tijdschaalbereik