【发布时间】:2015-02-06 13:29:40
【问题描述】:
我想知道如何确定四位 STD_LOGIC_VECTOR 中是否有多个位设置为“1”。
例如,如果它是“1001”或“1100”或“1111”。
我正在编写一个程序,如果我的实体收到多个控制信号,我必须将错误信号设置为“1”。四个控制信号已合并为一个 4 位 STD_LOGIC_VECTOR,我需要一种智能方法来确定是否设置了多个位。
【问题讨论】:
我想知道如何确定四位 STD_LOGIC_VECTOR 中是否有多个位设置为“1”。
例如,如果它是“1001”或“1100”或“1111”。
我正在编写一个程序,如果我的实体收到多个控制信号,我必须将错误信号设置为“1”。四个控制信号已合并为一个 4 位 STD_LOGIC_VECTOR,我需要一种智能方法来确定是否设置了多个位。
【问题讨论】:
我解决了
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", 也应该可以工作:可以说更整洁一些。
您的向量足够小,因此蛮力解决方案是一种相当简单的方法(您的合法值比非法值少,因此检查合法值会更容易)。你也可以使用一个函数(在这里概括):
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) >= 2的饱和加法。
bits_set(v) > 1 减少到单个 4 输入 LUT。不错!
与 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) > 1,并且“N out”列是从bits_set(v) 输出的
获取表达式时 QII 做了多少减少的参考
bits_set(v) > 1.
bits_set(v) > 1的优化对于QII来说显然有些坎坷,
如 16 左右的“Add > 1”列所示,但 QII 确实使用 bits_set(v) > 1 表达式
减少逻辑,而不是仅仅做一个愚蠢的比较。
【讨论】:
当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;
理由是:
要检查 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 => '1');
基本上你想检查向量是否是 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;
我没有空运行代码(我猜缺少一些类型转换),但它应该可以很好地扩展。
【讨论】: