2
votes

Verilog se développe chaque bit n fois

Je veux développer chaque bit n fois. Par exemple,

logic [63 : 0] x;
logic [511 : 0] y;
genvar i;
for (i = 0; i < 64; i = i + 1) begin
    always_comb begin
        y[(i + 1) * 8 - 1 : i * 8] = x[i] ? 8'hFF : 8'h00;
    end
end

Existe-t-il un moyen simple (c'est-à-dire ne pas utiliser generate block) dans Verilog ou SystemVerilog?

EDIT 19.02.21

En fait, je fais une conversion de masque 64 bits en masque 512 bits, mais c'est différent de {8 {quelque chose}}. Mon code actuel est le suivant:

// n = 2
5'b10101 -> 10'b1100110011
// n = 3
5'b10101 -> 15'b111000111000111

Je me demande simplement qu'il existe une manière plus "belle".


6 commentaires

Non, il n'y a aucun moyen dans Verilog de le faire de manière simple. Bien que vous puissiez utiliser un opérateur de répétition pour créer des groupes de répétition, par exemple {2'b11, {2 {4'b0011}}}


@Serge Merci pour la réponse. En fait, j'ai besoin de cette fonctionnalité pour convertir le bitmask en bytemask. Par exemple, 3'b010 -> 24'h00FF00 Je demande, comme vous semblez expert en verilog, y a-t-il une manière «recommandée» de le faire? Actuellement, j'utilise generate block pour itérer sur chaque bit.


vous devez fournir un exemple de code. Cela peut être une solution spécifique à votre code. Très probablement, une fonction fera l'affaire.


Si vous passez de bit en octet, je pense que votre «n» est toujours 8. Ensuite, vous pouvez utiliser {8 {your_bit}}


Lorsqu'il s'agit de largeurs de bits dans Verilog, il existe différentes approches si vous savez que N est une constante ainsi que les opérandes de l'expression.


@Serge j'ai fourni un exemple de code


3 Réponses :


0
votes

Ma réponse n'est peut-être pas la meilleure des réponses, mais si j'étais vous, je ferais quelque chose comme ci-dessous (en supposant que x et y sont des registres dans votre module qui seront utilisés dans une conception synchrone):

module mask_conversion(

input [63:0] x;
output [511:0] y;

);

assign y[0+:8] = x[0] ? 8'hff : 8'h00;
assign y[8+:8] = x[1] ? 8'hff : 8'h00;
assign y[16+:8] = x[2] ? 8'hff : 8'h00;
assign y[24+:8] = x[3] ? 8'hff : 8'h00;
assign y[32+:8] = x[4] ? 8'hff : 8'h00;
              *
              *
              *
assign y[504+:8] = x[63] ? 8'hff : 8'h00;

endmodule

Pour des conditions toujours différentes:

// your module name and ports

reg [63:0] x;
reg [511:0] y;

// your initializations

always@('some sensitivity conditions') begin

y[0+:8] <= x[0] ? 8'hff : 8'h00;
y[8+:8] <= x[1] ? 8'hff : 8'h00;
y[16+:8] <= x[2] ? 8'hff : 8'h00;
y[24+:8] <= x[3] ? 8'hff : 8'h00;
y[32+:8] <= x[4] ? 8'hff : 8'h00;
              *
              *
              *
y[504+:8] <= x[63] ? 8'hff : 8'h00;
end

Cependant, si je voulais un module séparé qui entre x et sort y, je ferais quelque chose comme ci-dessous:

// your module name and ports

reg [63:0] x;
reg [511:0] y;

// your initializations

always@(posedge clk) begin

y[0+:8] <= x[0] ? 8'hff : 8'h00;
y[8+:8] <= x[1] ? 8'hff : 8'h00;
y[16+:8] <= x[2] ? 8'hff : 8'h00;
y[24+:8] <= x[3] ? 8'hff : 8'h00;
y[32+:8] <= x[4] ? 8'hff : 8'h00;
              *
              *
              *
y[504+:8] <= x[63] ? 8'hff : 8'h00;
end

Ce n'est pas si difficile de taper tout cela, il vous suffit de copier et coller, et de changer les nombres manuellement. En conséquence, vous obtiendrez un code garanti qui fait ce que vous voulez.


2 commentaires

Je pense que taper tout cela est plus sujet aux erreurs que de faire une boucle for (vous pourriez obtenir une erreur sur une ligne ici et ce bogue sera plus difficile à trouver qu'une erreur dans la boucle for). C'est également moins pratique si vous souhaitez changer.


@Moberg Vous avez raison à 100% !!! Personne n'utilise cette méthode, pas même moi :) Merci



3
votes

Je pense que votre méthode est bonne. Vous ne pouvez pas le faire sans une sorte de boucle (sauf si vous voulez taper toutes les itérations manuellement). Il peut y avoir plusieurs variantes pour l'implémenter.

Par exemple, utiliser l'opérateur '+:' au lieu d'une expression, ce qui le simplifie un peu.

function logic [511 : 0] transform(input logic [63 : 0] x);
 for (int j = 0; j < 64; j++) begin
  transform[j * 8 +: 8] = x[j] ? 8'hFF : 8'h00;
 end
endfunction
...
always @* begin
 y = transform(x);
end

La méthode ci-dessus a en fait généré 64 code > bloque toujours (comme dans votre original). Bien que la liste de sensibilité de chaque bloc ne soit qu'un seul bit de 'x'.

Vous pouvez déplacer la boucle for à l'intérieur d'un bloc always:

always @* begin
 for (int j = 0; j < 64; j++) begin
  y3[j * 8 +: 8] = x[j] ? 8'hFF : 8'h00;
 end
end

cela se terminera par un seul bloc always, mais la liste de sensibilité inclura tous les bits de 'x'.

Si cette opération est utilisée plusieurs fois, vous pouvez utiliser une fonction:

genvar i;
for (i = 0; i < 64; i = i + 1) begin
 always_comb begin
  y[i * 8 +: 8] = x[i] ? 8'hFF : 8'h00;
 end
end


1 commentaires

L'opérateur ternaire peut également être écrit comme une réplication y [i * 8 +: 8] = {8 {x [i]}};



1
votes

Si n est un paramètre, vous pouvez faire:

always_comb begin
  y = '0;
  foreach(y[idx]) begin
    y[idx] = x[ idx/n ];
  end
end

Si n est un signal, vous devez affecter chaque bit:

always_comb begin
  y = '0;
  for(int idx=0; idx<($bits(y)/n) && idx<$bits(x); idx++) begin
    y[idx*n +: n] = {n{x[idx]}};
  end
end

Un diviseur variable ajoutera une surcharge de temps et de surface. En fonction de votre objectif de conception, cela peut ou non être un problème (optimisation de la synthèse ou simulation uniquement).


0 commentaires