在VHDL中.....如何计算向量的前导零?

时间:2013-05-13 12:21:32

标签: vhdl fpga

我在VHDL项目中工作,我面临着计算向量长度的问题。我知道有一个矢量的长度属性,但这不是我正在寻找的长度。例如,我有std_logic_vector

    E : std_logic_vector(7 downto 0);  

然后

    E <= "00011010";

所以,len = E'length = 8但我不是在寻找这个。我想在丢弃最左边的零后计算len,所以len = 5;

我知道我可以通过从左到右检查“0”位来使用for循环,如果出现“1”位则停止。但这并不高效,因为我有1024或更多位,这将减慢我的电路。那么有没有任何方法或算法以有效的方式计算长度?例如使用log(n)级门的组合门,(其中n =比特数)。

4 个答案:

答案 0 :(得分:5)

你的“计数”与对数(基数2)非常相似。

这通常用于VHDL中,以确定表示信号所​​需的位数。例如,如果要在RAM中存储多达N个元素,则寻址该RAM所需的位数为ceil(log2(N))。为此,我使用:

function log2ceil(m:natural) return natural is
begin -- note: for log(0) we return 0
    for n in 0 to integer'high loop
        if 2**n >= m then
            return n;
        end if;
    end loop;
end function log2ceil;

通常,您希望在合成时使用常量执行此操作,并且速度无关紧要。但是你也可以生成FPGA逻辑,如果这真的是你想要的那样。

正如其他人所提到的,VHDL中的“for”循环仅用于生成查找表,由于信号路径较长,查找表可能很慢,但仍然只需要一个时钟。可能发生的是您的最大时钟频率下降。通常这只是一个问题,如果你操作大于64位的矢量(你提到1024位)和时钟快于100MHz。也许合成器已经告诉过你这是你的问题,否则我建议你先试试。

然后你必须在多个时钟上分割操作,并将一些中间结果存储到FF中。 (我会提前忘记尝试通过重新安排你的代码来超越合成器。查找表就是一个表。为什么你在这个表中生成值怎么重要?但是请确保你告诉合成器“不关心“如果你拥有它们的价值观。”

如果您关注速度,请使用第一个时钟并行检查所有16位块(彼此独立),然后使用第二个时钟周期将所有16位块的结果合并为一个结果。如果您需要考虑FPGA逻辑的数量,请实现一个状态机,在每个时钟周期检查一个16位块。

但请注意,在执行此操作时不要重新发明CPU。

答案 1 :(得分:2)

嗯,VHDL不是SW,它不需要时间来执行这样的操作,它只需要从FPGA中获取资源。

您可以将1024位数据划分为32位部分,并在所有位之间执行OR,这样,您一次检查32位。这并不是必需的,因为for循环可以完美地完成你想做的事情,只需编写代码,查找数组中的第一个1并停止循环并使用循环索引号作为指向第一个的指针数组中的1。我没有编译这段代码,但是这样的东西对你有用:

FirstOne <= 1023;
for i in E'reverse_range loop
  if (E(i) == '1') then
    FirstOne <= i;
    exit;
  end if;
end loop;

毕竟,它不会是FPGA中的大块。

答案 2 :(得分:2)

使用循环的问题在于,当你合成时,你可能会得到很长的逻辑链。

查看问题的另一种方法是找到最重要的设置位的索引。 为此,您可以使用优先级编码器。关于这一点的好处是您可以通过在树结构中使用较小的优先级编码器来制作大优先级编码器,因此延迟为O(log N)而不是O(N)。

这是一个4位优先级编码器: http://en.wikibooks.org/wiki/VHDL_for_FPGA_Design/Priority_Encoder 您可以使用其中5个块创建一个16位优先级编码器,然后使用来自五个16位编码器的256位编码器等。

但是因为你有这么多位,所以它会相当庞大。

答案 3 :(得分:0)

如今,大多数合成器都支持递归函数。事实上,这将为您提供与log(N)相当的复杂性,其中N是位数:

  • 将你的矢量分成两半
  • 如果上半部分全部为零
    • 你的答案的前导位是'1',低位取决于下半部分矢量
  • 否则
    • 你的答案的前导位是'0',低位取决于上半部分矢量
  • 递归上面选择的感兴趣的半矢量