如何删除systemverilog中动态数组中重复的连续元素?

How to remove the repeated consecutive elements in dynamic array in systemverilog?

module tb;
  
  bit [7:0] bytes [];
  bit [7:0] q[$];
  
  initial begin
    bytes = new[20];
    bytes[0] = 8'hee;
    bytes[1] = 8'hea;
    bytes[2] = 8'haf;
    bytes[3] = 8'haf;
    bytes[4] = 8'haf;
    bytes[5] = 8'h50;
    bytes[6] = 8'h6a;
    bytes[7] = 8'h0d;
    bytes[8] = 8'hc8;
    bytes[9] = 8'hc8;
    bytes[10] = 8'h21;
    foreach(bytes[i])
      $write("%h ", bytes[i]);
    $display("\n");
    q = bytes.unique();
    foreach(q[i])
      $write("%h ", q[i]);
  end
endmodule

在上面的代码中,我需要删除名为bytes的动态数组的连续重复元素(仅连续重复元素)并将它们放入名为q的队列中。另外,我需要删除所有尾随的 0。我尝试使用 unique(),但得到的结果有所不同。

预期输出:

ee ea af af af 50 6a 0d c8 c8 21 00 00 00 00 00 00 00 00 00 00

ee ea af 50 6a 0d c8 21

我在 edaplayground 上的 QuestaSim 上得到的输出

ee ea af af af 50 6a 0d c8 c8 21 00 00 00 00 00 00 00 00 00 00 
 
00 0d 21 50 6a af c8 ea ee

更多信息:

一旦为0,就不能重复。由于它是通过读取 DUT 接口上的数据值创建的动态数组,最后读取的值为 0,除非有新数据,否则保持为 0。

因为它的复制只是由于当前数据被保存在输出接口上(遵循一些仲裁优先级,等待下一个优先级端口数据的几个周期)。并且数据被约束随机化以具有唯一值(输入到 DUT 的数据)。

例如。我在端口 3 的输入上发送 a、b、c、d,端口 3 等待几个周期来检查是否请求了任何其他端口,因此输出可能类似于 bbb cc d(b 的 3 个周期和 2 个周期对于 c) 和动态数组读取此输出。去掉重复项是为了在Scoreboard中比较输入输出的等价性。

unique方法返回的队列中元素的顺序好像没有定义。那么,如何将您的队列更改为 ints:

的队列?
int q[$];

然后使用 unique_index:

q = bytes.unique_index();

然后在上面使用 sort 方法:

q.sort();

那么顺序就定义好了,不管你用什么模拟器。 (最好编写适用于任何模拟器的代码)。所以,我们现在有一个索引队列,我们​​可以用它来索引原始数组 (byte):

foreach(q[i])
   $write("%h ", bytes[q[i]]);

这给了我这个输出(在 Aldec Riviera Pro 上):

ee ea af af af 50 6a 0d c8 c8 21 00 00 00 00 00 00 00 00 00 

ee ea af 50 6a 0d c8 21 00 

https://www.edaplayground.com/x/6pV6

module tb;
  
  bit [7:0] bytes [];
  int q[$];
  
  initial begin
    bytes = new[20];
    bytes[0] = 8'hee;
    bytes[1] = 8'hea;
    bytes[2] = 8'haf;
    bytes[3] = 8'haf;
    bytes[4] = 8'haf;
    bytes[5] = 8'h50;
    bytes[6] = 8'h6a;
    bytes[7] = 8'h0d;
    bytes[8] = 8'hc8;
    bytes[9] = 8'hc8;
    bytes[10] = 8'h21;
    foreach(bytes[i])
      $write("%h ", bytes[i]);
    $display("\n");
    q = bytes.unique_index();
    q.sort();
    foreach(q[i])
      $write("%h ", bytes[q[i]]);
  end
endmodule

您可以遍历原始数组,仅在连续项目不匹配时才将项目添加到新队列。这也删除了尾随 00.

module tb;
  
  bit [7:0] bytes [];
  bit [7:0] q[$];
  
initial begin
    bytes = new[20];
    bytes[0] = 8'hee;
    bytes[1] = 8'hea;
    bytes[2] = 8'haf;
    bytes[3] = 8'haf;
    bytes[4] = 8'haf;
    bytes[5] = 8'h50;
    bytes[6] = 8'h6a;
    bytes[7] = 8'h0d;
    bytes[8] = 8'hc8;
    bytes[9] = 8'hc8;
    bytes[10] = 8'h21;

    $display;
    foreach (bytes[i]) $write("%h ", bytes[i]);
    $display;

    q[0] = bytes[0];
    for (int i=1; i<bytes.size(); i++) begin
        if (bytes[i] != bytes[i-1]) q.push_back(bytes[i]);
    end
    if (q[$] == 0) void'(q.pop_back());

    foreach (q[i]) $write("%h ", q[i]);
    $display;
    $display;
end

endmodule

这输出:

ee ea af af af 50 6a 0d c8 c8 21 00 00 00 00 00 00 00 00 00 
ee ea af 50 6a 0d c8 21

这里是 edaplayground 上的演示。


关于 unique 数组方法,IEEE 标准 1800-2017,第 7.12.1 节 数组定位器方法,指出:

The ordering of the returned elements is unrelated to the ordering of the original array.

也许这意味着无法保证生成的顺序。使用您的代码,我们在 edaplayground (original code in Question) 的不同模拟器上得到混合结果;有些会产生您想要的输出顺序,而有些则不会。

module duplicateremoval;
int array[] = {1, 2, 3, 4, 5, 2, 3, 4, 6, 8, 3};

int i, j, k;
  
initial begin
  for(i=0 ; i<array.size()-1 ; i=i+1)
  begin
    for(j=i+1 ; j<array.size() ; j=j+1)         //j should be one step advanced to i
          begin
               if(array[i] == array[j])
                  begin
                       for(k=j ; k<array.size() ; k=k+1)
                            begin
                                 array[k] = array[k+1];
                             end
                     j--;
                    end
               end
    $display("array[%0d]=%0d", i, array[i]);
   end
 end        
endmodule

在此代码中,使用 for 循环将下一个值与当前值进行比较。如果当前值与下一个值相同,将跳过当前值并将下一个值分配给当前值。替换后,将迭代器减少 1,以便它位于当前位置。