如何在一个循环中将数组中的非零元素移动到顶部?

时间:2014-06-19 00:09:59

标签: verilog

我有以下8位数组:

0
4
0
0
5
0
2
0

如何在一个循环中完成以下操作(不逐个迭代元素)?

4
5
2
0
0
0
0
0

我知道如何在软件(MATLAB)中完成它,但我不知道如何使用组合逻辑。

% initialise temporary vectors
TempType = zeros(maxType,1);
TempStart = zeros(maxType,1);
TempStop = zeros(maxType,1);
index = 1;

% remove zero elements from the middle
for j = 1:maxType
    if (PreType(j) > 0 && PreStart(j) > 0 && PreStop(j) > 0)
        TempType(index) = PreType(j);
        TempStart(index) = PreStart(j);
        TempStop(index) = PreStop(j);
        index = index + 1;
    end
end

2 个答案:

答案 0 :(得分:3)

我认为任何简化的排序算法都可以完成这项工作。例如,以下是在单个周期中实施的修改后的冒泡排序解决方案:

module MoveZeros;
  parameter W1 = 8;
  parameter W2 = 10;
  integer i, j;
  logic [W1-1:0] array[W2-1:0] = {0,4,0,0,5,0,2,0,0,1};
  logic [W1-1:0] temp;


  always_comb begin
    for (i=W2-1 ; i >=0 ; i=i-1)
      for (j=W2-1 ; j >= 0 ; j=j-1)
    begin

      if (array[j]==0 && array[j-1] != 0) begin
        temp = array[j];
        array[j] = array [j-1];
        array[j-1] = temp;          
      end
    end
  end

endmodule


output:
# array = '{4, 5, 2, 1, 0, 0, 0, 0, 0, 0}

edaplayground上的工作示例。根据您的循环时间和输入数组的宽度(W2),您可能希望将此算法分解为多个循环。

合成工具展开循环,因此,合成电路将具有O(W2 ^ 2)比较器和多路复用器,它们可以爆炸。因此,对于更大的阵列,可以采用多周期解决方案。

答案 1 :(得分:0)

这不是一个答案,需要几个小时的工作,但是SO的评论不符合这类问题。你应该问comp.arch.fpga,它是否还活着。

首先找一个旧的异步直通FIFO的数据表;这些将包括电路图。你真的不想做这样的事情,因为阶段到阶段的握手是毛茸茸的,你不能同时应用所有8个值,但它会给你更多同步实现的想法。调整直通FIFO以实现您想要的功能是微不足道的 - 只需忽略零输入。

如果您可以使用最多8个时钟周期,则使用相对有限的硬件可以轻松实现更加同步的实现。

一个周期看起来并不太难,但会使用更多的硬件。你有多确定你必须在一个周期内完成它?你可以使用多少硬件?如果你有一个免费的PLL / DLL,我倾向于使用它来获得8倍的时钟。

修改

实际上,考虑到超过2分钟的好处,即使在一个周期内,这似乎也很容易。

假设您的8个输入(I0-I7)和8个输出寄存器(Q0-Q7)有8个寄存器。每个输出寄存器都有相关的逻辑,用于选择源数据的输入寄存器。 Q0选择器找到包含非零数据的编号最小的I寄存器。 Q1选择器找到包含非零数据的下一个最高I寄存器,依此类推。每个选择器驱动一个mux,它加载相应的输出寄存器。 Q0需要8-1 mux(I0-I7的8个8位输入,1个8位输出,进入Q0的输入)。 Q1需要7-1 mux(输入只能是I1-I7),依此类推,直到Q7,根本不需要多路复用器(它只能由I7驱动)。

选择器中唯一的智能是查找每个输出寄存器的源数据。 Q7选择器很简单; Q7只能选择I7,并且只有当所有I0-I7都包含非零数据时。 Q6有点复杂,等等。

如果您看不到如何编码选择器,请在新问题中专门询问该选择器,以避免所有注释。