I have a signal "event_id" where only one of the bits is high at any time. I need to convert this one-hot encoded signal to an integer-value of the index.
The signals:
signal event_id: std_logic_vector(3 downto 0);
signal event_index: natural;
I know I can do this with a for-loop. This is what I'm currently doing:
for i in 3 downto 0 loop
if(event_id(i) = '1') then
event_index = i;
end if;
end loop;
Is there a better way to do this that doesn't require a for-loop or going through each bit individually? I know I could make a function with the for-loop method, but I feel like there should be a simple solution that I'm missing.
There is no "simple" solution for generating the index of a one-hot vector in VHDL.
For a one-hot vector of 4 bits, thus a resulting index of 2 bits, the loop you have made is an OK solution, that is readable and does not take up too much resources in implementation. Though it is not the smallest solution, since it does not allow the implementation size to benefit from the one-hot property, as it returns the lowest index of a set bit. For short one-hot vectors this does not matter if the implementation is in an FPGA, since it uses quantized LUT resources.
For longer one-hot vectors the implementation will be smaller if the one-hot property is used. This can be done with an algorithm where the index bits are generated from the one-hot vector and a mask. A function for this is shown below.
-- One hot to index calculate; assuming LEN_HOT = 2 ** LEN_IDX
function hot2idx_cal(hot : std_logic_vector) return std_logic_vector is
variable mask_v : std_logic_vector(LEN_HOT - 1 downto 0);
variable res_v : std_logic_vector(LEN_IDX - 1 downto 0);
begin
for i in 0 to LEN_IDX - 1 loop
-- Generate mask
for j in 0 to LEN_HOT - 1 loop
if ((j / (2 ** i)) mod 2) = 0 then
mask_v(j) := '0';
else
mask_v(j) := '1';
end if;
end loop;
-- Apply mask and generate bit in index
if unsigned(hot and mask_v) = 0 then
res_v(i) := '0';
else
res_v(i) := '1';
end if;
end loop;
return res_v;
end function;