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’:
- when pressing btn(0) the state of the 8 switches loads correctly into the data_reg
- when I press the btn(1), the LEDs are all ON (“111…11”)
- if I press btn(2), the LEDs display the data_reg contents
- If no button is pressed, the state of the LEDs is that commanded by the last button press
Behavior ‘b’:
- when pressing btn(0) the state of the 8 switches loads correctly into the data_reg
- when I press btn(1), the LEDs display the data_reg contents
- if I press btn(2), the LEDs are all ON (“111…11”)
- If no button is pressed, all LEDs are ON & the only way to see the contents of the data_reg is to hold btn(1) depressed.
`
process(clk)
begin
if (clk'event and clk='1') thenif (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;
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”