SystemVerilog中具有可变宽度的位切片

问题描述

我试图使用+:运算符访问数组的某些部分,但是遇到了臭名昭著的[variable] is not a constant错误。唯一的问题是,我希望从数组中获取的宽度也在改变。

这是我的循环:

logic [N-1:0] a;
logic [2**N-2:0] b;
for (i = 0; i < N; i++)
    a[i] = b[(2**i)-1 +: 2**i] == {(2**i){1'b1}};

换句话说,如果是N = 4,我希望此循环执行此操作:

a[0] = b[0:0] == 1'b1;
a[1] = b[2:1] == 2'b11;
a[2] = b[6:3] == 4'b1111;
a[3] = b[14:7] == 8'b11111111;

从逻辑上讲,我可以确定我提供的循环可以正常工作,但是SystemVerilog不允许使用非常量来设置宽度(在a:之后)。 当我的起始索引和宽度都依赖于非常数变量时,如何利用+:运算符?还是考虑到N可以是一个大数字呢?

谢谢!

编辑:

这可以通过轮班完成,这是一个工作代码

for (i = 0; i < N; i++)
    a[i] <= ((b >> (2**i)-1) << ((2**N) - (2**i) - 1)) == 
             {(2**N-1){1'b1}} << ((2**N) - (2**i) - 1);

解决方法

您不能将+:使用可变宽度。实际上,它只是换挡和遮挡的捷径。例如,以下情况应适用于您的情况:

  logic [N-1:0] a;
  logic [2**N-2:0] b;
  always_comb begin
   for (int i = 0; i < N; i++) begin
    logic [2**N-2:0] tmpb,tmp1;
    tmpb = b >> ((2**i)+1);
    tmp1 = ((2**N)'(1) <<  (2**i)) - 1;
    a[i] = (tmpb & tmp1) == 0;
   end
  end

您只需要弄清楚移位和宽度的确切数目即可。

,

您可以结合使用'+:`运算符和掩码

   parameter N  = 8; localparam N2 = 2**(N-1);
   logic [N-1:0] a;
   logic [2**N-1:0] b;

   initial begin
      b       ={8'b000001,4'b1111,2'b01,1'b1};
      for (int i = 0; i < N; i++)
          a[i]  = (b[(2**i)-1 +: N2] | ~N2'((1 << 2**i)- 1)) == '1;
      $displayb(a,b);
      end
,

如果右侧是常数或+:,则可以使用genvar

logic [N-1:0] a;
logic [2**N-2:0] b;
for (genvar i = 0; i < N; i++) begin : gen_a
    assign a[i] = b[(2**i)-1 +: 2**i] == {(2**i){1'b1}};
end

请注意,此for循环是一个不包含在程序块(即begin-end中)的for循环