Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VHDL : Multiple rising_edge detections inside a process block

I'm pretty new to VHDL (and digital circuits in general), and I'm trying to implement a counter of two digits using BCD style blocks. External to this circuit there is going to be buttons, which when pressed, will bump the digit of interest up by one (much like an alarm clock would). This is an asynchronous action, and will occur when in some form of edit mode (externally enforced). The code I have written works fine without the "elsif rising_edge(digitUp1) then" and "elsif rising_edge(digitUp1) then" blocks, but fails with them included. I really have no idea why it doesn't work or how I can fix it. Keep getting errors like "couldn't implement registers for assignments on this clock edge", "can't infer register for count2[3] because its behavior depends on the edges of multiple distinct clocks" and "Can't infer register for "count2[3]" at MinuteCounter.vhd(21) because it does not hold its value outside the clock edge". Any help would be greatly appreciated.

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;

-- ToDo: ENFORCE ON ALL COUNTERS (externally) LOGIC TO PAUSE AT MAX/MIN

entity MinuteCounter is
port( clockIn, digitUp1, digitUp2, reset, counting, countUp : in std_logic;
      clockOut : out std_logic;
      BCD1, BCD2 : out std_logic_vector(3 downto 0));
end MinuteCounter;

architecture structure of MinuteCounter is
signal count1, count2 : std_logic_vector(3 downto 0);
signal carryOut : std_logic;
begin

process( clockIn, digitUp1, digitUp2, countUp, reset, counting)
begin 

    -- Asynchronous reset
    if reset = '1' then
        count1 <= "0000";
        count2 <= "0000";

    -- What to run when there's an active edge of the clock
    elsif rising_edge(clockIn) then

        -- Code to run when timer is running
        if counting = '1' then

            -- What to do when counting up
            if countUp = '1' then
                if ((count1 = "1001") and (count2 = "0101")) then
                    count1 <= "0000";
                    count2 <= "0000";
                    if carryOut = '0' then
                        carryOut <= '1';
                    else
                        carryOut <= '0';
                    end if;
                elsif count1 = "1001" then
                    count1 <= "0000";
                    count2 <= count2 + 1;
                else
                    count1 <= count1 + 1;
                end if;

            -- What to do when counting down (This logic is hard to understand)
            else
                if ((count1 = "0000") and (count2 = "0000")) then
                    count1 <= "1001";
                    count2 <= "0101";
                    if carryOut = '0' then
                        carryOut <= '1';
                    else
                        carryOut <= '0';
                    end if;
                elsif count1 = "0000" then
                    count1 <= "1001";
                    count2 <= count2 - 1;
                else
                    count1 <= count1 - 1;
                end if;
            end if;

        -- When counting is disabled, but there is an active edge (do nothing)
        else
            count1 <= count1;
            count2 <= count2;
        end if;

    -- Code to run when entering values (will not be run if counting = '1') << Externally enforced
    elsif rising_edge(digitUp1) then
        if count1 = "1001" then
            count1 <= "0000";
            count1 <= count1 + 1;
        else
            count1 <= count1 + 1;
        end if;

    -- Code to run when entering values (will not be run if counting = '1') << Externally enforced
    elsif rising_edge(digitUp2) then
        if count2 = "0101" then
            count2 <= "0000";
            count2 <= count2 + 1;
        else
            count2 <= count2 + 1;
        end if;

    -- What to do when there is no active edge or other events (nothing)
    else
        count1 <= count1;
        count2 <= count2;
    end if;

end process;

-- Assign outputs
BCD1 <= count1;
BCD2 <= count2;
clockOut <= carryOut;

end structure;
like image 568
balsamfir Avatar asked Dec 15 '22 04:12

balsamfir


1 Answers

The "why it doesn't work" is explained in the question title : Multiple rising_edge detections inside a process block.

VHDL is designed to describe hardware, and there is no basic circuit element that responds to multiple clock signals. So you cannot describe a circuit that way.

So how do you fix it?

You transform the circuit into one where any single process only has one clock signal (and optionally, one asynchronous reset signal as you are using correctly). This can be implemented using real registers and flip flops.

Two ways are :

  1. several processes, using signals to communicate between them
  2. A single process, with a single clock, sampling the other signals on the main clock edge.

The correct decision between these requires some overall knowledge of the design.

Here it sounds as if all three clock signals are actually button presses, rather than one fast clock. Therefore you cannot guarantee that there will be a clock edge while another button is pressed.

So here is one of many ways forward : make a clock signal (outside the process) which will cover all three input events.

my_clock <= clockIn or digitUp1 or digitUp2;

Now you can rewrite the process using this clock:

process(my_clock, reset) is
begin
   if reset = '1' then
      -- reset actions
   elsif rising_edge(my_clock) then
      -- what caused this event?
      if digitUp1 = '1' then      -- bump digit 1
      elsif digitup2 = '1' then   -- bump digit 2
      else                        -- count normally
      endif;
   end if;
end process;

Notes:

  1. As this is a proper synchronous process, only clock and reset belong in the sensitivity list.
  2. Though this will work in a sense, it may not be what the customer wants : what happens if he holds down all three buttons for example? You may want to explore other approaches to the design.
like image 106
user_1818839 Avatar answered Feb 24 '23 13:02

user_1818839