【问题标题】:Verilog expand each bit n timesVerilog 将每个位扩展 n 次
【发布时间】:2019-07-13 23:06:47
【问题描述】:

我想将每个位扩展 n 次。 例如,

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

在 Verilog 或 SystemVerilog 中有没有简单的方法(即不使用生成块)?

编辑 19.02.21

其实我是在做 64 位掩码到 512 位掩码的转换,但它与 {8{something}} 不同。我当前的代码如下:

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

我只是想知道还有更多“美丽”的方式。

【问题讨论】:

  • 不,verilog 中没有办法以简单的方式做到这一点。尽管您可能会使用重复运算符来执行重复组,例如{2'b11, {2{4'b0011}}}
  • @Serge 谢谢你的回复。实际上,我需要这个功能来将位掩码转换为字节掩码。例如,3'b010 -&gt; 24'h00FF00 我问,您似乎是 verilog 专家,有什么“推荐”的方法吗?目前,我正在使用生成块来迭代每一位。
  • 您需要提供代码示例。它可能是特定于您的代码的解决方案。 function 很可能会这样做。
  • 如果你从一个字节到另一个字节,我认为你的'n'总是8。那么你可以使用{8{your_bit}}
  • 在 Verilog 中处理位宽时,如果您知道 N 是常数以及表达式中的操作数,则有不同的方法。

标签: verilog system-verilog


【解决方案1】:

我的答案可能不是最好的答案,但如果我是你,我会做以下事情(假设 x 和 y 是模块中将用于同步设计的寄存器):

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

对于不同的总是条件:

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

但是,如果我想要一个单独的模块来输入 x 和输出 y,我会执行以下操作:

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

输入所有这些并不难,您只需要复制和粘贴,并手动更改数字。因此,您将获得有保证的代码,可以满足您的需求。

【讨论】:

  • 我相信输入所有这些内容比执行 for 循环更容易出错(您可能会在此处的一行中遇到错误,并且该错误将比 for 循环中的错误更难找到)。想换也不太方便。
  • @Moberg 你是 100% 正确的!!!没有人使用这种方法,甚至我也没有:)谢谢
【解决方案2】:

我认为你的方法很好。如果没有某种循环,您就无法做到这一点(除非您想手动输入所有迭代)。实现它可能有几种变体。

例如,使用 '+:' 运算符代替表达式,这会稍微简化一些。

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

上面的方法实际上生成了64 总是阻塞(就像你原来的那样)。虽然每个块的敏感度列表将只是'x'的一个位。

您可以将 for 循环移动到 always 块中:

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

这将最终成为一个始终阻止,但敏感度列表将包括“x”的所有位。

如果多次使用这个操作,可以使用一个函数:

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

【讨论】:

  • 三元运算符也可以写成复制y[i * 8 +: 8] = {8{x[i]}};
【解决方案3】:

如果n 是一个参数,你可以这样做:

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

如果n 是一个信号,你必须分配每个位:

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

变量除数会增加时序和面积开销。根据您的设计目标,它可能是也可能不是问题(仅限综合优化或仿真)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    • 2011-07-29
    • 1970-01-01
    • 2018-03-15
    相关资源
    最近更新 更多