1

I am writing code for comparing a signal to a number of signals at the same time.

Here is the example:

process (CLK, reset)
if reset = '0' then
    data <= (others => '0');
elsif rising_edge (CLK) then 
    if A = B then
         data <= data OR "0001";
    else data <= data AND "1110";
    end if;

    if A = C then
        data <= data OR "0010";
    else data <= data AND "1101";
    end if;

    if A = D then
        data <= data OR "0100";
    else data <= data AND "1011";
    end if;

    if A = E then
        data <= data OR "1000";
    else data <= data AND "0111";
    end if;
end if;
end process;

I just want to comparing the A to B, C, D and E signals and then turn the associated bits in data on and off. The code I wrote above is not working since the synthesis tool will optimize the B, C and D if statements and only leaving the E if statement. I have also thought about using case - when statement but it doesn't have a mechanism to turn off the associated single bit off. When others can only turn all 4 bits off. What is the effective way to do this? Thanks!

BTW, are all these 4 if statements run at the same time? Or they are run at different cycles? I guess they would run one by one, otherwise it would cause fan-in.

nigong
  • 1,727
  • 3
  • 19
  • 33

1 Answers1

2

You are trying to write C in a language where you don't have to! In C you can't access a single bit, only bytes and larger units so C programmers have to resort to AND/OR i.e. &,| to set or clear bits.

In VHDL you can address individual bits of a word, and write

if A = B then
     data(0) <= '1';
else 
     data(0) <= '0';
end if;

Much simpler. And yes they all run at the same time, every clock cycle.

I would prefer to declare data as an array of booleans,

signal data : array(3 downto 0) of boolean;

Then I could write

process (CLK, reset)
begin
   if reset = '0' then
      data <= (others => false);
   elsif rising_edge (CLK) then 
      data <= (A = E) & (A = D) & (A = C) & (A = B);
   end if;
end process;

If I had to use a std_logic_vector for data, the convenience of this form is (almost) tempting enough to make me overload the "=" operator for A's type with one returning std_logic. Then, for the price of writing a tiny function, I could keep this code.

EDIT: To address the reason the original approach doesn't work, it is necessary to understand the semantics of signal assignment, as explained for example here.

So the first assignment to Data (for A=B) is stored up to happen after the process suspends. Then the second assignment replaces it BEFORE IT HAPPENED so the first such assignment never takes place.

What you need for the original approach to work, is a variable because variable assignments happen immediately.

process (CLK, reset)
    variable data_int : whatever; -- same type as data
begin
if reset = '0' then
    data <= (others => '0');
elsif rising_edge (CLK) then 
    data_int := data;
    if A = B then
         data_int := data_int OR "0001";
    else data_int := data_int AND "1110";
    end if;
    ...
    if A = E then
         data_int := data_int OR "1000";
    else data_int := data_int AND "0111";
    end if;

    data <= data_int;

end if;
end process;

Now the single assignment to data will contain all the separate modifications. However it might synthesise to something much larger than the optimal solutions.

MahMoos
  • 1,014
  • 9
  • 16
  • Your way works! Thanks a lot. To my curiosity, is it because my method is causing the fan-in so that the lower 3 bits are optimized? – nigong Apr 30 '13 at 23:42