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".
3 Réponses :
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.
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
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
L'opérateur ternaire peut également être écrit comme une réplication y [i * 8 +: 8] = {8 {x [i]}};
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).
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