2017-07-12 4 views
5

J'utilise SystemVerilog pour la synthèse. Je me suis battu avec le fait que les tableaux d'interfaces ne sont pas vraiment des tableaux dans SystemVerilog et l'index doit être une valeur constante, mais il a surmonté les instructions generate for et assign pour surmonter ce qui est vraiment une limitation de la langue (si je peux émuler l'effet en utilisant plus de code, la langue pourrait juste faire la bonne chose (tm) elle-même).Tableaux d'instances d'interface dans SystemVerilog avec nombre d'éléments paramétrés

Pour le pseudo-code suivant, j'omets une grande partie de ce qu'il y a dans le code réel (modports, tâches, etc) pour plus de clarté. J'ai une interface:

interface i_triplex(); 
logic a;    // input wire 
logic b;    // output wire 
logic [127:0] data; // output wires 
endinterface 

Et je passe un tableau de ces interfaces à un module qui ressemble à

module roundrobin_triplex#(
    parameter int NUNITS = 8 
) 
(
    input wire clk, 
    input wire rst, 
    i_triplex t[NUNITS] 
); 
always_ff @(posedge clk) begin 
    if (rst) begin 
     // insert code to initialize the "data" member 
     // in all interface instances in the array. 
    end 
    else begin 
     // ... 
    end 
end 
endmodule 

Quelle serait votre manière préférée d'utiliser toutes les instances d'interface dans le tableau uniforme - - indépendamment de la valeur de NUNITS? J'ai quelques suggestions, mais j'ai hâte d'apprendre ce que d'autres ingénieurs peuvent imaginer.

Suggestion 1: Utilisez VHDL.

Proposition 2: Scrap l'interface et faire oldschool Verilog style, comme dans

module roundrobin_triplex#(
    parameter int NUNITS = 8 
) 
(
    input wire clk, 
    input wire rst, 
    // This was once a proud i_triplex array 
    input wire i_triplex_a[NUNITS], 
    input wire i_triplex_b[NUNITS], 
    input wire [127:0] i_triplex_data[NUNITS], 
); 
always_ff @(posedge clk) begin 
    if (rst) begin 
     for (int i = 0; i < NUNITS; i++) 
      i_triplex_data[i] <= '1; 
    end 
    else begin 
     // ... 
    end 
end 
endmodule 

Suggestion 3: Utiliser un struct pour les fils d'entrée et une struct pour les fils de sortie au lieu de L'interface.

Suggestion 4: Utilisez un système comme préprocesseur qui se déroule generate for boucles à l'intérieur des processus (ce que la langue doit faire de toute façon!), De sorte que le code résultant ressemble (prétraité avec Nunits = 4):

module roundrobin_triplex#(
    parameter int NUNITS = 8 
) 
(
    input wire clk, 
    input wire rst, 
    i_triplex t[NUNITS] 
); 
always_ff @(posedge clk) begin 
    if (rst) begin 
     i_triplex.data[0] <= '1; 
     i_triplex.data[1] <= '1; 
     i_triplex.data[2] <= '1; 
     i_triplex.data[3] <= '1; 
    end 
    else begin 
     // ... 
    end 
end 
endmodule 

Suggestion 5: Utiliser la solution generate for/assign:

module roundrobin_triplex#(
    parameter int NUNITS = 8 
) 
(
    input wire clk, 
    input wire rst, 
    i_triplex t[NUNITS] 
); 

wire i_triplex_a[NUNITS]; 
wire i_triplex_b[NUNITS]; 
wire [127:0] i_triplex_data[NUNITS]; 

generate 
genvar i; 
// The wires of the interface which are to be driven 
// from this module are assigned here. 
for (i = 0; i < NUNITS; i++) begin 
    assign t[i].b = i_triplex_b[i]; 
    assign t[i].data = i_triplex_data[i]; 
end 
endgenerate 

always_ff @(posedge clk) begin 
    if (rst) begin 
     for (int i = 0; i < NUNITS; i++) 
      i_triplex_data[i] <= '1; 
    end 
    else begin 
     // ... 
    end 
end 
endmodule 

Répondre

0

Suggestion 1: VHDL peut être pratique. Cependant, il semble devenir marginal dans l'industrie.

Suggestion 2: À mon avis, les interfaces sont pertinentes si vous avez l'intention de les réutiliser largement et de mettre en place des protocoles de vérification. Si vous pouvez déballer votre interface comme ceci, tout en gardant votre santé mentale, je ne vois pas de justification pour une interface en premier lieu.

Suggestion 3: Je ne ai jamais essayé de synthétiser struct, il peut être une bonne idée.

Suggestion 4: Solution simple, bien que très verbeuse.

Suggestion 5: J'ai utilisé quelque chose de similaire pour un de mes projets. Cependant, j'ai écrit une sorte de module adaptateur pour cacher les affectations.
En fait, quand j'ai besoin de quelque chose comme ça, j'essaye d'écrire un module atomique qui fonctionne sur un nombre fixe d'interfaces. Ensuite, j'utilise for generate structures pour le généraliser sur un tableau d'interface.

1

Les tableaux d'instances de module ou d'interface ne peuvent pas être traités comme des tableaux réguliers car les paramétrages, les blocs générateurs et les instructions defparam peuvent rendre les éléments de l'instance de tableau non uniques. Cela ne peut pas arriver avec des tableaux de variables/fils.

Ma suggestion serait une modification de votre suggestion 2; mettre des tableaux de variables/fils dans une seule instance d'interface.

+0

Peut-être que la langue devrait être étendue pour vérifier si toutes les instances d'interface dans un tableau sont "assez similaires" (ou permettent à l'utilisateur d'utiliser un mot-clé pour l'indiquer) et permettent d'utiliser de tels tableaux d'instances d'interface comme des tableaux réguliers. Cela résoudrait * beaucoup * de problèmes lors de l'utilisation d'interfaces pour la synthèse. – apriori

+0

J'ai littéralement des centaines de modules utilisant cette interface, dont la plupart l'utilisent comme un port d'interface normal, mais beaucoup utilisent des choses comme 'i_triplex t [NUNITS + 2]' pour mux'ing avec d'autres instances d'interface. J'espère pouvoir passer sans trop réécrire le code, donc je vais vérifier si une combinaison de votre modification de la suggestion 2 et du code de la colle 'générer pour' 'for for-assign' fonctionnera donc je peux laisser la plupart des autres modules comme ils sont utilisez quelque chose comme une interface 'i_triplex_array' pour les occurrences où cela est bénéfique. – apriori

+0

Oui, je suis d'accord, nous aurions besoin d'une nouvelle syntaxe. Essayer de trouver des règles basées sur l'usage rend encore plus compliqué un langage déjà trop compliqué. –

0

suggestion que diriez-vous # 6, utilisez l'interface paramétrées:

interface I #(NPORTS = 8); 
    logic clk; 

    logic a[NPORTS]; 
    logic b[NPORTS]; 
    logic [127:0] data [NPORTS]; 

endinterface // 

module roundrobin#(NUMPORTS = 8) (I t); 
    logic [127:0] data[NUMPORTS]; 

    always_ff @(posedge t.clk) begin 
     data <= t.data; 
    end 

endmodule // roundrobin 

Notez que vous n'avez pas besoin de la boucle dans le système Verilog. vous pouvez utiliser les affectations de tableau:

data <= t.data; 

et pour des raisons de commodité, vous pouvez ajouter des fonctions ou des déclarations à l'interface elle-même, à savoir

interface I #(NPORTS = 8); 
    logic clk; 

    logic a[NPORTS]; 
    logic b[NPORTS]; 
    logic [127:0] data [NPORTS]; 

    function logic [127:0] getData(int n); 
     return data[n]; 
    endfunction // getData 

endinterface // I 

et utiliser

data[i] <= t.getData(i); 

Désolé, la L'exemple ci-dessus n'est probablement pas très utile, mais il pourrait vous donner une idée.

0

Peut-être que je manque quelque chose par pourquoi ne pas mettre tout le code vôtre de roundrobin_triplex en générer (vous n'avez pas besoin cessionnaires supplémentaires)

interface i_triplex(); 
    logic a;    // input wire 
    logic b;    // output wire 
    logic [127:0] data; // output wires 
    initial $fmonitor(1,data); 
endinterface 

module roundrobin_triplex#(parameter int NUNITS = 8) 
(
    input wire clk, 
    input wire rst, 
    i_triplex t[NUNITS] 
); 
    genvar i; 
    for(i=0; i<NUNITS; i++)begin 
     always_ff @(posedge clk) begin 
      if (rst) begin 
       t[i].data <=0; 
      end 
      else begin 
       t[i].data <=t[i].data+1; 
      end 
     end 
    end 
endmodule 

module top; 
    parameter P=4; 
    bit clk,rst; 
    i_triplex ii[P](); 
    roundrobin_triplex #(P)uut(clk,rst,ii); 
    initial begin 
     rst=1; 
     repeat(2) @(posedge clk); 
     rst=0; 
     repeat(10) @(posedge clk); 
     $finish; 
    end 
    always #5 clk =~clk; 
endmodule