3
\$\begingroup\$

I've inherited some VHDL code I need to extend. There's a piece in there that looks like a bug to me, but while I'm long-time C developer, I've no experience in VHDL. I understand that processes essentially run in parallel, but within a process, does order matter? In the following code, a CPLD is receiving serial ADC data from a microcontroller. The data stream contains the results from two separate 8-bit conversions and is being loaded into two registers, one bit at a time. However it looks like at the end of receiving the first byte of ADC data, the MSB of this byte is being overwritten with the MSB from the second byte before it's loaded into its register. Is this a bug? I've removed some of the code to make the sample more readable.

LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity CPLD is port(
   ADC_Clk              : in  std_logic;
   ADC_Data             : in  std_logic;
end CPLD;

architecture arch_CPLD of CPLD is
   signal   ADC_Counter : std_logic_vector (7 downto 0);
   signal   ADC_Reg_1   : std_logic_vector (7 downto 0);
   signal   ADC_Temp    : std_logic_vector (7 downto 0);

begin

-- Shift in data from two 8-bit ADC channels
--   ADC_Counter incremented by another process on rising edge of ADC_Clk
ADC_Shift: process(ADC_Clk)
begin
   if (falling_edge(ADC_Clk))  then

      -- Shift in 8 bits from ADC data channel 1
      if    (ADC_Counter = 5 ) then   -- skip over sync bits
            ADC_Temp(7) <= ADC_Data;  -- get MSB of data
      elsif (ADC_Counter = 6 ) then
            ADC_Temp(6) <= ADC_Data;

      -- code omitted for clarity :      getting bits 5 to 1      

      elsif (ADC_Counter = 12 ) then
            ADC_Temp(0) <= ADC_Data;  -- get LSB of data

      -- shift in 8 bits from ADC data channel 2      
      elsif (ADC_Counter = 13 ) then
             ADC_Temp(7) <= ADC_Data; -- BUG? Overwriting MSB with next byte?
             ADC_Reg_1 <= ADC_Temp;   -- first byte of data to Register 1

      elsif (ADC_Counter = 14 ) then  -- continue getting second byte
            ADC_Temp(6) <= ADC_Data;

      -- code omitted for clarity

      end if;
   end if;
end process ADC_Shift;
end arch_CPLD;
\$\endgroup\$
  • \$\begingroup\$ What happens when you simulate the code? Does it work the way you expect it should? \$\endgroup\$ – Joe Hass Apr 29 '14 at 19:05
  • \$\begingroup\$ @JoeHass A good question, but unfortunately I haven't yet learned how to use the simulator. \$\endgroup\$ – Allen Moore Apr 29 '14 at 22:26
5
\$\begingroup\$

Not knowing all the details, in principle it is not a bug. This is a process that occurs whenever there is a falling edge on the associated clock. You can imagine that all signal reads happen right before the edge, and all the writes happen at the edge.

So having inside a clocked process:

a <= b; -- after the edge, a will have the contents of b
c <= a; -- after the edge, c will have the contents of a (NOT THE CONTENTS OF b).

The order of the above assignments does not matter, and can be represented by the following schematic:

schematic

simulate this circuit – Schematic created using CircuitLab

As you can see in the above schematic, each Flip-Flop has a 'queued' value Dand it becomes the output Q at the clock's edge. a has b queued, and c has a queued. So in a single clock, b can't propagate all the way to c (it requires 2 clock cycles). So specifying the signal 'queuing' in code does not need any particular order.

In your specific example, when ADC_Counter is 13, ADC_temp(7) has ADC_Data queued, and ADC_Reg_1 has ADC_Temp queued. ADC_Reg_1 is not getting corrupted with the new data bit, in the same way that our c is not getting corrupted with b.

Note: This would be different if talking about variables (you'd be using the := operator instead of <=), but your code only contains signals.

\$\endgroup\$
2
\$\begingroup\$

If ADC_Temp was a variable, you would be right. However it's a signal, and signals are VHDL's inter-process communication mechanism; a (very!) little like pipes to a C programmer.

Thus the OLD value in ADC_Temp is available at the assignment to ADC_Reg_1, despite this assignment following an assignment to ADC_Temp.

What actually happens to the first assignment in that it is postponed - scheduled to actually take place once the process has suspended, therefore the old ADC_Temp value is still preserved at the time of the second assignment.

The organisation of signal assignments in this way is sometimes called VHDL's "crown jewel" and it eliminates the race conditions that plague other simulation technologies. More info here and here...

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.