Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Industrial programming >> Verilog

Maîtriser les blocs generate Verilog : Instanciation dynamique et conception conditionnelle

Un bloc generate permet de multiplier instances de modules ou faire instanciation conditionnelle. Il permet de construire la conception basée sur paramètres Verilog. Particulièrement pratique quand même opération/instance doit être répétée plusieurs fois ou si code doit être inclus conditionnellement selon paramètres.

Bloc generate ne peut contenir déclarations port, paramètre, specparam ou blocs specify. Autres éléments modules et blocs generate autorisés. Toutes instanciations generate codées dans module entre generate et endgenerate.

Instanciations générées : modules, affectations continues, blocs always/initial, primitives utilisateur. Trois types :

Boucle generate for

Demi-additionneur instancié N fois dans module top-level my_design via generate for loop. Variable boucle déclarée avec genvar indiquant usage pendant élaboration generate.

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

// Top-level avec N instances demi-additionneur
module my_design #(parameter N=4) (input [N-1:0] a, b, output [N-1:0] sum, cout);
genvar i; // Variable boucle temporaire pour génération, pas dispo simulation
generate
for (i = 0; i < N; i = i + 1) begin
    ha u0 (a[i], b[i], sum[i], cout[i]);
end
endgenerate
endmodule

Testbench

Paramètre testbench contrôle nombre instances demi-additionneur. N=2 -> 2 instances.

module tb; parameter N = 2; reg [N-1:0] a, b; wire [N-1:0] sum, cout;
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],b[0] -> sum[0],cout[0] ; a[1],b[1] -> sum[1],cout[1].

Simulation Log :

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.

RTL élaboré a bien 2 instances demi-additionneur générées par bloc generate.

Maîtriser les blocs generate Verilog : Instanciation dynamique et conception conditionnelle

Generate if

Exemple if else dans generate pour choisir entre 2 implémentations multiplexeur. Design #1 utilise assign, #2 utilise case. Paramètre USE_CASE dans top-level pour choisir.

// Design #1: Mux avec assign
module mux_assign (input a, b, sel, output out);
assign out = sel ? a : b;
initial $display ("mux_assign instancié"); endmodule

// Design #2: Mux avec case
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
initial $display ("mux_case instancié"); endmodule

// Top Level: paramètre pour choisir
module my_design (input a, b, sel, output out);
parameter USE_CASE = 0;
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

Testbench

Instancie my_design avec USE_CASE=1 -> instancie design avec case.

module tb; reg a, b, sel; wire out; integer i;
my_design #(.USE_CASE(1)) u0 (.a(a), .b(b), .sel(sel), .out(out));
initial begin a <= 0; b <= 0; sel <= 0;
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

USE_CASE=1 -> mux_case instancié (visible dans log). USE_CASE=0 -> mux_assign instancié.

Simulation Log :

// USE_CASE = 1
ncsim> run mux_case is instantiated i=0 a=0x0 b=0x0 sel=0x0 out=0x0 ...
// USE_CASE = 0
ncsim> run mux_assign is instantiated i=0 a=0x0 b=0x0 sel=0x0 out=0x0 ...

Generate Case

Generate case permet instancier modules, blocs initial/always basé sur expression case pour choisir parmi plusieurs options.

// Design #1: Demi-additionneur
module ha (input a, b, output reg sum, cout);
always @ (a or b) {cout, sum} = a + b; initial $display ("Demi-additionneur instancié"); endmodule

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

// Top level: choix entre demi et 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

Testbench

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

Note : demi-additionneur instancié -> cin n'affecte pas sorties.

Simulation Log :

ncsim> run Half adder instantiation a=0x0 b=0x0 cin=0x0 cout=00 sum=0x0 ...
ncsim: *W,RNQUIE: Simulation is complete.

Verilog

  1. Maîtriser Verilog : Tutoriel complet pour la conception de circuits numériques
  2. Maîtriser la concaténation Verilog : Guide pratique
  3. Verilog Essentiel : Aperçu concis
  4. Comprendre les affectations Verilog : Types, Syntaxe et Bonnes Pratiques
  5. Verilog Blocking vs Non-Blocking : Différences Clés Expliquées
  6. Maîtriser les Fonctions Verilog pour une Conception RTL Efficace
  7. Comprendre les Tasks Verilog : Fonctions vs Tasks, Syntaxe et Utilisation
  8. Générateur d'Horloge Verilog : Guide de Conception et d'Implémentation
  9. Maîtriser les Fonctions Mathématiques Verilog pour une Conception Matérielle Efficace