irobot
irobot

Reputation: 31

if elsif vhdl behavior

I am using webPack ISE v 13 to program a Nexys 3 board with the following piece of code and notice completely different behavior by swapping statements in the if elsif statement. In essence, I'm using three pushbuttons on the board: when pressing the first pushbutton btn(0), the state of 8 switches is stored in a register. When I press btn(1), the state of the switches should be displayed in the 8 leds and the leds should keep this state. When I press btn(2), I force all leds to be lit and they should stay this way if neither btn 1 or 2 is pressed. By swapping the actions under the if and elsif for buttons 1 & 2, the behavior changes: the state of the switches is only displayed when I press the corresponding button and once I let go, all LEDs light up.

More than looking for a "this is what you need to make it work", I'm after an explanation of why vhdl behaves so differently from C++ let's say (in this instance where the order wouldn't matter)

Below is the code excerpt; I indicate which lines to comment/uncomment to get behavior 'a' or behavior 'b'.

Behavior 'a':

Behavior 'b':

`

process(clk)

begin

if (clk'event and clk='1') then
   if (db_btn(0)='1') then          --load sw state into data_reg
      data_reg <= sw;
   end if;

end if; end process;

   process(btn,data_reg)
   begin
     if btn(1)='1' then 
        data_s2f <= "1111111111111111";   --behvr a; comment this line for behvr b
        -- data_s2f <= "00000000" & data_reg; -- uncomment for behvr b; comment for behvr a
     elsif btn(2)='1' then -- read     
       data_s2f <= "00000000" & data_reg; --behvr a; comment this line for behvr b
       --data_s2f <= "1111111111111111";  -- uncomment for behvr b; comment for behvr a
      end if;
   end process;
   -- output
   led <= data_s2f(7 downto 0);  --display data_s2f in LEDs

SIMULATION TESTBENCH

Here is my simulation testbench. Whenever I executed the result for all signals is UUU..UU Any comments would be greatly appreciated:

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;

ENTITY ifstmt_tb IS
END ifstmt_tb;

ARCHITECTURE behavior OF ifstmt_tb IS 

    -- Component Declaration for the Unit Under Test (UUT)

    COMPONENT ram_ctrl_test
    PORT(
         clk : IN  std_logic;
         reset : IN  std_logic;
        sw : IN  std_logic_vector(7 downto 0);
        btn : IN  std_logic_vector(2 downto 0);
        led : OUT  std_logic_vector(7 downto 0)
        );
    END COMPONENT;


   --Inputs
  signal clk : std_logic := '0';
  signal reset : std_logic := '0';
  signal sw : std_logic_vector(7 downto 0) := (others => '0');
  signal btn : std_logic_vector(2 downto 0) := (others => '0');

    --Outputs
   signal led : std_logic_vector(7 downto 0);

   -- Clock period definitions
   constant clk_period : time := 10 ns;

BEGIN

    -- Instantiate the Unit Under Test (UUT)
   uut: ram_ctrl_test PORT MAP (
          clk => clk,
          reset => reset,
          sw => sw,
          btn => btn,
          led => led
        );

   -- Clock process definitions
   clk_process :process
   begin
        clk <= '0';
        wait for clk_period/2;
        clk <= '1';
        wait for clk_period/2;
   end process;


   -- Stimulus process
   stim_proc: process
   begin        
      -- hold reset state for 100 ns.
        reset <= '1';
        sw <= "11001100";
        btn<= (others => '0');
      wait for 100 ns;  
        reset <= '0';
      wait for clk_period*10;
        -- load register
        btn<= (0=>'1', others => '0');
       wait for clk_period*2;   
        btn<= (others => '0');  
       wait for clk_period*10;  
        -- display with btn 1
        btn<= (1=>'1', others => '0');
       wait for clk_period*5;   
        btn<= (others => '0');  
       wait for clk_period*10;  
        -- display with btn 2
        btn<= (2=>'1', others => '0');
       wait for clk_period*5;   
        btn<= (others => '0');  
       wait for clk_period*10;  
        -- change pattern
        sw <= "11100111";
        wait for clk_period;
        -- load register
        btn<= (0=>'1', others => '0');
       wait for clk_period*2;   
        btn<= (others => '0');  
       wait for clk_period*10;  
        -- display with btn 2
        btn<= (2=>'1', others => '0');
       wait for clk_period*5;   
        btn<= (others => '0');  
       wait for clk_period*10;  
        -- display with btn 1
        btn<= (1=>'1', others => '0');
       wait for clk_period*5;   
        btn<= (others => '0');  

      -- insert stimulus here         

      wait;
   end process;  

END;

Upvotes: 2

Views: 4564

Answers (3)

Paul Seeb
Paul Seeb

Reputation: 6146

VHDL executes if statements sequentially with cascading enables driving the output of your various conditional statements. All of the conditions are completely calculated all the time (lets ignore propagation delay for this point). The hardware "selects" the first statement that meets your conditions (the output from subsequent if elsif branches drive the enables for lower statements so if one evaluates to false the next is enabled).

I think the behavior you see does appear "odd" but in reality what do you expect. If you don't give a default value you will get unexpected results based on the hardware. You need to program in black and white. Right now you are programming gray. VHDL is much less forgiving with programmer intent. You must always be definitive and explicit.

One potential answer is that this is not the best way to code this if statement. A better method would be to create a "tick" signal indicating a "sure" button depress which drives a separate sequential latching process recording the depressed option. I imagine the behavior you see is hardware dependent and hence difficult to explain.

One other point that is not mentioned here is that you should implement a switch debouncer. Effectively the switch might be toggling a lot when held down and acting in a manner you dont expect (wire it up to an oscilliscope and put it in edge mode and youll see). You should count for a time period (eg 1ms) while a switch is depressed and only switch on after that period. Same for turning off. This might do better to buffer any bounciness you might have. This is how you would make your "sure" button depress "tick"

Upvotes: 3

Voider
Voider

Reputation: 454

It sounds like the hardware for btn(2) is throwing more '1's then you expect, or is otherwise getting a high signal more often. See if mapping to a different hardware button helps. Make sure btn (2) is set up in a pullup mode rather than pull down.

As for the code portion, be aware that the structure is a nested if, so you will see a difference in behavior when BOTH btn(1) and btn(2) are high.

Upvotes: 1

Martin Thompson
Martin Thompson

Reputation: 16802

In addition to checking the behaviour with a simulator...

  • Are you sure that your switches are mapped to the correct pins on the FPGA?
  • Are the switches wired such that pressing them produces a 1 - sometimes they float to a 1 and produce 0 when pressed.

Upvotes: 0

Related Questions