【问题标题】:How to determine if more than one bit in an STD_LOGIC_VECTOR is set in VHDL如何确定是否在 VHDL 中设置了 STD_LOGIC_VECTOR 中的多个位
【发布时间】:2015-02-06 13:29:40
【问题描述】:

我想知道如何确定四位 STD_LOGIC_VECTOR 中是否有多个位设置为“1”。

例如,如果它是“1001”或“1100”或“1111”。

我正在编写一个程序,如果我的实体收到多个控制信号,我必须将错误信号设置为“1”。四个控制信号已合并为一个 4 位 STD_LOGIC_VECTOR,我需要一种智能方法来确定是否设置了多个位。

【问题讨论】:

    标签: vhdl bit


    【解决方案1】:

    我解决了

    with selvec select
    ERR <=  '0' when "0001",
            '0' when "0010",
            '0' when "0100",
            '0' when "1000",
            '0' when "0000",
            '1' when others;
    

    不是最简洁的代码,但可以解决问题。

    【讨论】:

    • when "0000"|"0001"|"0010"|"0100"|"1000", 也应该可以工作:可以说更整洁一些。
    【解决方案2】:

    您的向量足够小,因此蛮力解决方案是一种相当简单的方法(您的合法值比非法值少,因此检查合法值会更容易)。你也可以使用一个函数(在这里概括):

    function bits_set(v : std_logic_vector) return natural is
      n : natural := 0;
    begin
      for i in v'range loop
        if v(i) = '1' then
          n := n + 1;
        end if;
      end loop;
      return n;
    end function bits_set;
    

    不确定如何合成,但应该足够了。 正如下面在 cmets 中所指出的,对于 n=4,这实际上似乎在 Quartus 中合成得相当好,至少。我很想知道其他工具的表现如何。正如 Morten 所说,它本来可以更有效地编码,尤其是对于更大的位数(所以作为一个通用的解决方案,我想它比实际有用的更具说明性)。

    【讨论】:

    • 当您只需要指示多个位集时,可以将高达 ceil(log2(v'length + 1)) 位宽的 v'length - 1 加法器更改为一些简单的门。
    • 我希望综合工具能够足够聪明地解决这个问题......但是,对于这个特定的应用程序,逻辑可能要简单得多。
    • 一个好的综合工具可能可以将加法器的长度减少到最小,但很难将加法器转换为基于最终bits_set(v) &gt;= 2的饱和加法。
    • 你确定吗?我通过 Quartus 运行它进行检查,它使用函数(完全按照编写的)将比较 bits_set(v) &gt; 1 减少到单个 4 输入 LUT。不错!
    • 有趣;让我深入研究这个问题,我做了一个答案以获得更好的空间和格式。
    【解决方案3】:

    与 cmets 到 fru1tbat 答案相关,用于检测多个位集的替代函数可以是:

    function bits_set_two_or_more(v : std_logic_vector) return std_logic is
      variable one_or_more : std_logic := '0';
      variable two_or_more : std_logic := '0';
    begin
      for i in v'range loop
        if one_or_more = '0' then
          one_or_more := v(i);
        else  -- one_or_more = '1'
          two_or_more := two_or_more or v(i);
        end if;
      end loop;
      return two_or_more;
    end function;
    

    使用 Altera Quartus II (QII) 综合到 Cyclone V 器件,具有大量 空格,显示在下面的“或”列中,其中“添加 > 1”列是 bits_set(v) &gt; 1,并且“N out”列是从bits_set(v) 输出的 获取表达式时 QII 做了多少减少的参考 bits_set(v) &gt; 1.

    bits_set(v) &gt; 1的优化对于QII来说显然有些坎坷, 如 16 左右的“Add > 1”列所示,但 QII 确实使用 bits_set(v) &gt; 1 表达式 减少逻辑,而不是仅仅做一个愚蠢的比较。

    【讨论】:

    • 感谢您为此付出的努力!我注意到对于更大的宽度,优化开始失效,但我并没有走这么远。
    【解决方案4】:

    v 设置了n 位时,以下函数返回true。

    function is_nhot(v: std_logic_vector; n: natural) return boolean is
        variable ret : boolean;
        constant s   : std_logic_vector(v'length-1 downto 0) := v;
    begin
        if n = 0 then
            ret := s = (s'length-1 downto 0 => '0');
        else
            if s'length < n then
                ret := false;
            elsif s'length = n then
                ret := s = (s'length-1 downto 0 => '1');
            else
                ret := ((s(s'length-1) = '1') and is_nhot(s(s'length-2 downto 0),n-1))
                    or ((s(s'length-1) = '0') and is_nhot(s(s'length-2 downto 0),n));
            end if;
        end if;
        return ret;
    end function;
    

    理由是:

    1. 如果输入字符串 s 的位数少于 n,则不能设置 n 位
    2. 如果 s 的长度为 n 位,则必须全部设置
    3. 如果 s 多于 n 位,则递归执行比较

    要检查 std_logic_vector 是否设置了 2 位或更多位,请使用

    if not (is_nhot(v,0) or is_nhot(v,1)) then ...
    

    【讨论】:

    • elsif s'length = n then 下,我怀疑你的意思是ret := s = (s'length-1 downto 0 =&gt; '1');
    • 我标记的语句无法编译。您错过了与某物的比较(实际上,您正在尝试将聚合分配给布尔值)。
    • 我误读了您的第一条评论。是的,你是对的,我已经改变了那个语句,它现在应该可以编译了。
    【解决方案5】:

    基本上你想检查向量是否是 2 的幂。看看https://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2

    -- Taking the formula from the link above
    -- f = (v & (v - 1)) == 0;
    if (v and (v - 1)) > 0 then
       -- at least 2 bits are set, hence an error occured
    end if;
    

    我没有空运行代码(我猜缺少一些类型转换),但它应该可以很好地扩展。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-09
      • 1970-01-01
      • 2016-11-12
      • 2021-04-09
      • 1970-01-01
      • 2023-03-15
      • 1970-01-01
      • 2018-12-08
      相关资源
      最近更新 更多