Reputation: 419
I am wondering how I can determine if more than one bit of a four-bit STD_LOGIC_VECTOR is set to '1'.
e.g if it is "1001" or "1100" or "1111".
I am writing a program where I have to set an error signal to '1' if I get more than one control signal to my entity. The four control signals have been merged into one 4-bit STD_LOGIC_VECTOR and I need a smart way to determine if more than one of the bits are set.
Upvotes: 3
Views: 10019
Reputation: 179
Basically you want to check if the vector is a power of two. Take a look at 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;
I did not dry run the code (i guess some typecasts are missing), but it should scale pretty well.
Upvotes: 0
Reputation: 1297
The following function returns true when v
has n
bits set.
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;
The rationale is:
To check if a std_logic_vector has 2 or more bits set, use
if not (is_nhot(v,0) or is_nhot(v,1)) then ...
Upvotes: 0
Reputation: 15924
Related to comments to fru1tbat answer, an alternative function for detection of more than one bit set can be:
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;
Synthesis with Altera Quartus II (QII) to Cyclone V device with plenty of
space, is shown in the "Or" column below, where "Add > 1" column is
bits_set(v) > 1
, and "N out" column is output from bits_set(v)
to have a
reference for how much reduction QII does when getting the expression
bits_set(v) > 1
.
The optimization for bits_set(v) > 1
is apparently a little bumpy for QII,
as shown in "Add > 1" column around 16, but QII does actually use the bits_set(v) > 1
expression to
reduce the logic instead of just doing a dumb compare.
Upvotes: 1
Reputation: 1625
Your vector is small enough that a brute-force solution is a reasonably simple way to go (you have fewer legal values than illegal values, so checking the legal values would be easier). You could also use a function (generalized here):
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;
Not sure how that will synthesize, but it should be sufficient. As noted below in the comments, for n=4, this actually appears to synthesize rather well in Quartus, at least. I would be curious to hear how other tools perform. As Morten says, it could have been coded more efficiently, especially for larger bit counts (so as a generalized solution, it's more illustrative than actually useful as-is, I suppose).
Upvotes: 2
Reputation: 419
I solved it with
with selvec select
ERR <= '0' when "0001",
'0' when "0010",
'0' when "0100",
'0' when "1000",
'0' when "0000",
'1' when others;
Not the neatest code but it does the trick.
Upvotes: 3