Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

VHDL Deal Or No Deal Synthesis Problem

Status
Not open for further replies.

kmb32123

Newbie level 4
Joined
Dec 6, 2012
Messages
5
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,340
I am currently working on a project to replicate a game similar to the game show Deal or No Deal. I have a decent amount of experience programming circuits in a single state via entities but this is my first attempt at a state machine. I do have a lot of experience with higher languages like java and c but those have proven to be little help. The inability for me to 'step though' code is getting me pretty frustrated. When I load the following code onto the board it seems to produce random output and I'm not sure where to start debugging. I have tried making changes and again, the effects seem unpredictable. Currently when the reset switch is on I can tell it is in the 'initiate' state because the seven segment displays display 0000. However, when I turn off the reset switch it seems to move to a different state without any other input from me. I was under the understanding that by this code it should continue to be in the 'initiate' state until it receives the confirm_in signal. Then on the other hand I could be wrong, I just would like another perspective from someone who knows more about this process.

For those of you who don't know how the game is played, a contestant chooses between one of many closed briefcases, each containing a dollar value. In my application each of the 10 case will be represent by an LED. The case the contestant chose is kept closed. After the contestant chooses there case, they select another case. This newly selected case is opened and the dollar value is displayed. Then, based on the probability of a high value in the contestant's case, they are offered a dollar value from the 'banker' to sell it for. It is at this point the contestant must choose deal or no deal. If they select deal, they sell their unopened case to the banker and receive the offer amount from the banker and the game ends. Otherwise they select another case to open and see the value. They are then offered another value. This continues until there is one unopened case left. At this point the contestant must chose to take the final offer or open their case and receive that value.


mytypes.vhd
Code:
Library ieee;
use ieee.std_logic_1164.ALL;
use ieee.std_logic_arith.ALL;

PACKAGE mytypes IS 
			type segArray is array (0 to 9) of bit_vector(6 downto 0);
			type boxArray is array (0 to 9) of NATURAL;
			type seven_seg_vector is array (natural range <>) of bit_vector(6 downto 0);
			subtype number_of_seven_segs is integer range 0 to 3;
			subtype number_of_red_leds is integer range 0 to 9;
END PACKAGE mytypes;

DealOrNoDeal.vhd
Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.math_real.all; 
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;

library work;
use work.mytypes.all; 

entity DealOrNoDeal is
    Port ( clk, rst : IN  STD_LOGIC;
           left_in, right_in, confirm_in, decline_in : IN  STD_LOGIC;
		   SevenSegs : out seven_seg_vector( number_of_seven_segs );
		   LEDs : out std_logic_vector( number_of_red_leds ));
		


		signal sevSegKey : segArray := ("1000000", "1111001", "0100100", "0110000", "0011001",
		                      "0010010", "0000011", "1111000", "0000000", "0011000");

		

           
    function random ( max : NATURAL) return NATURAL is
		variable rand: real;
		variable s1 : positive := 1;
		variable s2 : positive := 1;
		begin
	    
		UNIFORM(s1, s2, rand);
		return (INTEGER(TRUNC(rand*1000.0)) MOD max);
	end function random;
	
	function toSevenSeg ( num : NATURAL ) return seven_seg_vector is
		variable output: seven_seg_vector( number_of_seven_segs );
		begin
		for I in number_of_seven_segs loop
			output(I) := sevSegKey((num / (10 ** I)) MOD 10);
		end loop;
		return output;
	end function toSevenSeg;
	
	function toLogic ( num : NATURAL ) return STD_LOGIC is
		begin
			IF(num = 0 ) THEN
				RETURN '0';
			END IF;
			RETURN '1';
	end function toLogic;
	
	function setLEDs(key : boxArray) return std_logic_vector is
		variable output:std_logic_vector( number_of_red_leds );
		begin
			FOR I IN number_of_red_leds LOOP
				output(I) := toLogic (key(I));
			END LOOP;
			return output;
	end function setLEDs;
	
	function setBoxes return boxArray is
		variable boxValKey : boxArray := (1, 5, 10, 25, 50, 75, 100, 500, 750, 1000);
		variable result : boxArray := (0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
		variable rand : NATURAL := random (10);
		begin
			FOR I IN number_of_red_leds LOOP
				while ( boxValKey( rand ) = 0 ) LOOP
					rand := (rand + 3) MOD 10;
				END LOOP;
				result(I) := boxValKey( rand );
				boxValKey(rand) := 0;
			END LOOP;
		return result;
	end function setBoxes;
	
	function adjustPosition ( left : BOOLEAN; right : BOOLEAN; ledIndex : INTEGER) return NATURAL is
		begin
		IF (NOT(left XOR right)) THEN 
			return ledIndex;
		END IF;
		IF(LEFT) THEN
			return (ledIndex - 1) MOD 10;
		END IF;
		return (ledIndex + 1) MOD 10;
	end function adjustPosition;
	
	function getOffer(key : boxArray) return POSITIVE is
		variable sum : NATURAL := 0;
		variable num : NATURAL := 0;
		begin
			FOR I IN number_of_red_leds LOOP
				IF(key(I) /= 0) THEN
					sum := sum + key(I);
				    num := num + 1;
				END IF;
			END LOOP;
			sum := sum / num;
			return sum;
	end function getOffer;
	
end DealOrNoDeal;

architecture fsm of DealOrNoDeal IS
	TYPE state IS (initiate, start_selector, mid_selector, display_value, offer_prompt);
	SIGNAL present_state, next_state: STATE;
	SIGNAL boxes : boxArray;
	SIGNAL selectedBoxValue : NATURAL := 0;
	SIGNAL myBoxValue : NATURAL := 0;
	SIGNAL blinkDelay : NATURAL := 0;
	SIGNAL highlitLED : integer range 0 to 9;
	SIGNAL blinkState : std_logic;

begin
	
	
	PROCESS(rst, clk)
	BEGIN
		IF(rst='1') THEN
			present_state <= initiate;
		ELSIF(clk' EVENT AND clk ='1') THEN
			present_state <= next_state;
		END IF;
	END PROCESS;
	
	PROCESS(present_state, left_in, right_in, confirm_in, decline_in, boxes,  next_state,selectedBoxValue, myBoxValue, blinkDelay, highlitLED, blinkState)

	BEGIN
		
		CASE present_state IS

			--State to initiate signals
			--User presses confirm_in to move to next state
			WHEN initiate =>
				boxes <= setBoxes;
				highlitLED <= 0;
				blinkState <= '0';
				SevenSegs <= toSevenSeg (0);
				
				IF ( confirm_in = '1' ) THEN
					next_state <= start_selector;
				ELSE
					next_state <= present_state;
				END IF;

			--State for the user to select their personal case
			--All cases will be illuminated and the highlitLED flashes
			--left_in and right_in adjust highlitLED left and right
			--confirm_in stores boxes(highlitLED) for latter use and disallows this elemet to be selected later
			WHEN start_selector =>
				LEDs <= setLEDs(boxes);
				
				--Supposed to make LEDs(highlitLED) blink
				IF(blinkDelay > 100000)THEN
					blinkState <= NOT blinkState;
					blinkDelay <= 0;
				ELSE
					blinkDelay <= blinkDelay + 1;
				END IF;
				
				LEDs(highlitLED) <= blinkState;
				
				IF ( ( confirm_in = '1' ) AND boxes(highlitLED) /= 0 ) THEN
					next_state <= mid_selector;
					myBoxValue <= boxes(highlitLED);
					boxes(highlitLED) <= 0;
				ELSE
					next_state <= present_state;
					highlitLED <= adjustPosition (left_in = '1', right_in = '1', highlitLED);
				END IF;
				
			--State for the user to select a case to open
			--All unselected cases will be illuminated and the highlitLED flashes
			--left_in and right_in adjust highlitLED left and right
			--confirm_in stores boxes(highlitLED) for latter use and disallows this elemet to be selected later
			WHEN mid_selector =>
				LEDs <= setLEDs(boxes);
				
				--Supposed to make LEDs(highlitLED) blink
				IF(blinkDelay > 100000)THEN
					blinkState <= NOT blinkState;
					blinkDelay <= 0;
				ELSE
					blinkDelay <= blinkDelay + 1;
				END IF;
				
				LEDs(highlitLED) <= blinkState;
				
				IF ( (confirm_in = '1') AND boxes(highlitLED) /= 0 ) THEN
					next_state <= display_value;
					selectedBoxValue <= boxes(highlitLED);
					SevenSegs <= toSevenSeg (boxes(highlitLED));
					boxes(highlitLED) <= 0;
				ELSE
					next_state <= present_state;
					highlitLED <= adjustPosition ((left_in = '1'), (right_in = '1'), highlitLED);
				END IF;
				
			--State to display the value of the case the user just opened
			--Goes to next state when the user presses confirm_in
			WHEN display_value =>
				IF ( (confirm_in = '1') ) THEN
					next_state <= offer_prompt;
				ELSE
					next_state <= present_state;
				END IF;
				
			--State to offer the user a price for their case
			--confirm_in accepts the offer and restarts the game
			--decline_in sends the user to select another case
			WHEN offer_prompt =>
				SevenSegs <= toSevenSeg (getOffer(boxes));
				IF ((confirm_in = '1')) THEN
					next_state <= initiate;
				ELSIF ((decline_in = '1')) THEN
					next_state <= mid_selector;
				ELSE
					next_state <= present_state;
				END IF;
		END CASE;
	END PROCESS;
END fsm;

DealOrNoDeal.vhd - revised 12/06/12
Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.math_real.all; 
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;

library work;
use work.mytypes.all; 

entity DealOrNoDeal is
    Port ( clk, rst : IN  STD_LOGIC;
           left_in, right_in, confirm_in, decline_in : IN  STD_LOGIC;
		   SevenSegs : out seven_seg_vector( number_of_seven_segs );
		   LEDs : out std_logic_vector( number_of_red_leds ));	
end DealOrNoDeal;

architecture fsm of DealOrNoDeal IS

    function random ( max : NATURAL) return NATURAL is
		variable rand: real;
		variable s1 : positive := 1;
		variable s2 : positive := 1;
		begin
	    
		UNIFORM(s1, s2, rand);
		return (INTEGER(TRUNC(rand*1000.0)) MOD max);
	end function random;
	
	function toSevenSeg ( num : NATURAL ) return seven_seg_vector is
		variable output: seven_seg_vector( number_of_seven_segs );
		constant sevSegKey : segArray := ("1000000", "1111001", "0100100", "0110000", "0011001",
		                                  "0010010", "0000011", "1111000", "0000000", "0011000");
		begin
		for I in number_of_seven_segs loop
			output(I) := sevSegKey((num / (10 ** I)) MOD 10);
		end loop;
		return output;
	end function toSevenSeg;
	
	function toLogic ( num : NATURAL ) return STD_LOGIC is
		begin
			IF(num = 0 ) THEN
				RETURN '0';
			END IF;
			RETURN '1';
	end function toLogic;
	
	function setLEDs(key : boxArray) return std_logic_vector is
		variable output:std_logic_vector( number_of_red_leds );
		begin
			FOR I IN number_of_red_leds LOOP
				output(I) := toLogic (key(I));
			END LOOP;
			return output;
	end function setLEDs;
	
	function setBoxes return boxArray is
		variable boxValKey : boxArray;
		variable result : boxArray := (0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
		variable rand : NATURAL;
		begin
			boxValKey := (1, 5, 10, 25, 50, 75, 100, 500, 750, 1000);
			rand := random (10);
			FOR I IN number_of_red_leds LOOP
				while ( boxValKey( rand ) = 0 ) LOOP
					rand := (rand + 3) MOD 10;
				END LOOP;
				result(I) := boxValKey( rand );
				boxValKey(rand) := 0;
				rand := random (10);
			END LOOP;
		return result;
	end function setBoxes;
	
	function adjustPosition ( left : BOOLEAN; right : BOOLEAN; ledIndex : INTEGER) return NATURAL is
		begin
		IF (NOT(left XOR right)) THEN 
			return ledIndex;
		END IF;
		IF(LEFT) THEN
			return (ledIndex - 1) MOD 10;
		END IF;
		return (ledIndex + 1) MOD 10;
	end function adjustPosition;
	
	function getOffer(key : boxArray) return POSITIVE is
		variable sum : NATURAL := 0;
		variable num : NATURAL := 0;
		begin
			FOR I IN number_of_red_leds LOOP
				IF(key(I) /= 0) THEN
					sum := sum + key(I);
				    num := num + 1;
				END IF;
			END LOOP;
			sum := sum / num;
			return sum;
	end function getOffer;
          
	TYPE state IS (initiate, start_selector, mid_selector, display_value, offer_prompt);
	SIGNAL present_state, next_state: STATE;
	
	SIGNAL boxes : boxArray;
	SIGNAL selectedBoxValue : NATURAL := 0;
	SIGNAL myBoxValue : NATURAL := 0;
	SIGNAL highlitLED : integer range 0 to 9;

begin
	
	
	PROCESS(rst, clk)
	BEGIN
		IF(rst='1') THEN
			present_state <= initiate;
		ELSIF(clk' EVENT AND clk ='1') THEN
			present_state <= next_state;
		END IF;
	END PROCESS;
	
	PROCESS(rst, clk, highlitLED)
		constant max_count : natural := 48000000;
		variable count : natural range 0 to max_count;
    begin
        if rst = '0' then
            count := 0;
			LEDs <= setLEDs(boxes);
            LEDs(highlitLED) <= '1';

        elsif rising_edge(Clk) then
			LEDs <= setLEDs(boxes);
            if count < max_count/2 then
                LEDs(highlitLED)    <='1';
                count := count + 1;
            elsif count < max_count then
                LEDs(highlitLED)    <='0';
                count := count + 1;
            else
                count := 0;
                LEDs(highlitLED)    <='1';
            end if;
        end if;
    end process; 
	
	PROCESS(present_state, left_in, right_in, confirm_in, decline_in, selectedBoxValue, myBoxValue, highlitLED, boxes)

	BEGIN
		
		CASE present_state IS

			--State to initiate signals
			--User presses confirm_in to move to next state
			WHEN initiate =>
				selectedBoxValue <= 0;
				myBoxValue <= 0;
				highlitLED <= 0;
				boxes <= setBoxes;
				SevenSegs <= toSevenSeg (0);
				
				IF ( confirm_in = '1' ) THEN
					next_state <= start_selector;
				ELSE
					next_state <= present_state;
				END IF;

			--State for the user to select their personal case
			--All cases will be illuminated and the highlitLED flashes
			--left_in and right_in adjust highlitLED left and right
			--confirm_in stores boxes(highlitLED) for latter use and disallows this elemet to be selected later
			WHEN start_selector =>	
					
				selectedBoxValue <= 0;
				boxes <= boxes;
				SevenSegs <= toSevenSeg (1111);
				
				IF ( confirm_in = '1'  AND boxes(highlitLED) /= 0 ) THEN
					next_state <= mid_selector;
					myBoxValue <= boxes(highlitLED);
					boxes(highlitLED) <= 0;
					highlitLED <= 0;
				ELSE
					myBoxValue <= 0;
					next_state <= present_state;
					highlitLED <= adjustPosition (left_in = '1', right_in = '1', highlitLED);
				END IF;
				
			--State for the user to select a case to open
			--All unselected cases will be illuminated and the highlitLED flashes
			--left_in and right_in adjust highlitLED left and right
			--confirm_in stores boxes(highlitLED) for latter use and disallows this elemet to be selected later
			WHEN mid_selector =>

				myBoxValue <= myBoxValue;
				boxes <= boxes;
				SevenSegs <= toSevenSeg (2222);
				
				IF ( confirm_in = '1' AND boxes(highlitLED) /= 0 ) THEN
					next_state <= display_value;
					selectedBoxValue <= boxes(highlitLED);
					boxes(highlitLED) <= 0;
					highlitLED <= 0;
				ELSE
					selectedBoxValue <= 0;
					next_state <= present_state;
					highlitLED <= adjustPosition ((left_in = '1'), (right_in = '1'), highlitLED);
				END IF;
				
			--State to display the value of the case the user just opened
			--Goes to next state when the user presses confirm_in
			WHEN display_value =>
				selectedBoxValue <= 0;
				myBoxValue <= myBoxValue;
				highlitLED <= 0;
				boxes <= boxes;
				
				SevenSegs <= toSevenSeg (selectedBoxValue);
				IF ( confirm_in = '1' ) THEN
					next_state <= offer_prompt;
				ELSE
					next_state <= present_state;
				END IF;
				
			--State to offer the user a price for their case
			--confirm_in accepts the offer and restarts the game
			--decline_in sends the user to select another case
			WHEN offer_prompt =>
				selectedBoxValue <= 0;
				myBoxValue <= myBoxValue;
				highlitLED <= 0;
				boxes <= boxes;

				SevenSegs <= toSevenSeg (getOffer(boxes));
				IF ((confirm_in = '1')) THEN
					next_state <= initiate;
				ELSIF ((decline_in = '1')) THEN
					next_state <= mid_selector;
				ELSE
					next_state <= present_state;
				END IF;
		END CASE;
	END PROCESS;
END fsm;
 
Last edited:

First Question - have you testbenched it? where is your testbench code?

Secondly - you usually dont declare functions and signed in the entity part, they are usually declared inside the architecture. You would only put them in the entity declaration if you wanted the functions common accross several architectures, which is very rare. This is more a style thing and shouldnt be a problem.

Why have you bothered with the random function? It will give the same value every time you call it from the setBoxes function because you use a seed of 1 every time the function is called. The uniform function is not meant for syntesiable code, it is meant for testbenches only.

I am also a little scared at your use of functions. remember loops will unroll to parallel hardware, and while loops are only synthesisable if they can be unrolled with constant values. It makes me think you're a software guy having a go at VHDL. Did you draw the circuit out before you wrote any code? You should always do this before you write ANY VHDL. This is also highlighted by your use of counters in the asynchronous process. These will sum infinitely while in the state_selector state, it doesnt add when the state changes, it adds 1 as fast as it can until the state exits - and you end up with a latch because you havent assign blinkDelay in every single branch of every single state. (in an async process, you MUST assign EVERY signal in EVERY branch to avoid latches. And you cannot do counters in an async process.)

These are my first impressions. I suggest forgetting about the VHDL and drawing the circuit, and then re-thinking the VHDL.
 

    V

    Points: 2
    Helpful Answer Positive Rating
First Question - have you testbenched it? where is your testbench code?

I have not testbenched it. I was not aware of anyway to do this. I will certainly look into that later today and see what I find. If it works like I think it might this could be very helpful.

Secondly - you usually dont declare functions and signed in the entity part, they are usually declared inside the architecture. You would only put them in the entity declaration if you wanted the functions common accross several architectures, which is very rare. This is more a style thing and shouldnt be a problem.

Again, not aware of this but code uniformity never hurts. I will edit accordingly.

Why have you bothered with the random function? It will give the same value every time you call it from the setBoxes function because you use a seed of 1 every time the function is called. The uniform function is not meant for syntesiable code, it is meant for testbenches only.

Oh yah wow. That does make sence... So the 'Uniform' statement is meant to genereate random input for a testbench? Is there anyway then to produce that randomly 'unsorted' array.

I am also a little scared at your use of functions. remember loops will unroll to parallel hardware, and while loops are only synthesisable if they can be unrolled with constant values. It makes me think you're a software guy having a go at VHDL. Did you draw the circuit out before you wrote any code? You should always do this before you write ANY VHDL.

Deffinatly true. Always been software and now have a circuits class that decided to skim over VHDL in the last few weeks. As for the while loop here:
Code:
FOR I IN number_of_red_leds LOOP
	while ( boxValKey( rand ) = 0 ) LOOP
		rand := (rand + 3) MOD 10;
	END LOOP;
	result(I) := boxValKey( rand );
	boxValKey(rand) := 0;
END LOOP;
I just reliased that I never gave rand a new value after it found a good one. Will modify to:
Code:
FOR I IN number_of_red_leds LOOP -- For each breifcase
	while ( boxValKey( rand ) = 0 ) LOOP -- While the boxValKey( rand ) still has not been picked
		rand := (rand + 3) MOD 10; -- Increment value in the following order ( 0,3,6,9,2,5,8,1,4,7 )
	END LOOP;
	result(I) := boxValKey( rand ); -- result(I) gets the selected value
	boxValKey(rand) := 0; -- sets boxValKey(rand) to p
	rand := random (10); --Supposed to get new random number
END LOOP;
So the 'for loop' wil run 10 times, once for each case. Then the 'while loop' inside that will run from 0 to 9 times. It is gauraunteed to vistit every node in 10 iterations and the boxValKey will not be all zeros until the for loop has completely executed. So in theory it should work; just would have absolutely no idea on how to draw it out as a circuit.
This is also highlighted by your use of counters in the asynchronous process. These will sum infinitely while in the state_selector state, it doesnt add when the state changes, it adds 1 as fast as it can until the state exits - and you end up with a latch because you havent assign blinkDelay in every single branch of every single state. (in an async process, you MUST assign EVERY signal in EVERY branch to avoid latches. And you cannot do counters in an async process.)

I assume youre talking about these lines?

Code:
IF(blinkDelay > 100000)THEN
	blinkState <= NOT blinkState;
	blinkDelay <= 0;
ELSE
	blinkDelay <= blinkDelay + 1;
END IF;
				
LEDs(highlitLED) <= blinkState;

This is my feable attempt to turn an LED into a sort of blinking cursor. I want it to cycle on and off every 100000 clock cycles but now I realise that the clock has little to do with. So by async process you are refering to a process that doesnt detect clock events during it?

So would your sggection here be to make it its own process, counting when clk ='1'?

Thanks for the help!
 

So I decided to try simplifying down to a simple state machine and building from there.

Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.math_real.all; 
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;

library work;
use work.mytypes.all; 

entity DealOrNoDeal is
    Port ( clk, rst : IN  STD_LOGIC;
           switches_in	: in	std_logic_vector(3 downto 0);
		   SevenSegs : out seven_seg_vector( number_of_seven_segs );
		   LEDs : out std_logic_vector( number_of_red_leds ));	
end DealOrNoDeal;

architecture fsm of DealOrNoDeal IS
	
    	function toSevenSeg ( num : NATURAL ) return seven_seg_vector is
		variable output: seven_seg_vector( number_of_seven_segs );
		constant sevSegKey : segArray := ("1000000", "1111001", "0100100", "0110000", "0011001",
		                                  "0010010", "0000011", "1111000", "0000000", "0011000");
		begin
		for I in number_of_seven_segs loop
			output(I) := sevSegKey((num / (10 ** I)) MOD 10);
		end loop;
		return output;
	end function toSevenSeg;
	
	TYPE state IS (initiate, start_selector, mid_selector, display_value, offer_prompt);
	SIGNAL present_state, next_state: STATE;
	
begin
				
process (clk,rst)
begin
	if (rst='1') then
		present_state <= initiate;
	elsif (rising_edge(clk)) then
		present_state <= next_state;   --state change.
end if;
end process;


--state machine process.
PROCESS(present_state, switches_in)
begin
	case present_state is
		when initiate =>
			if(switches_in(1) ='1') then
				SevenSegs <= toSevenSeg (1111);
				next_state <= initiate;
			else
				SevenSegs <= toSevenSeg (1122);
				next_state <= start_selector;
			end if;   

		when start_selector =>
			if(switches_in(1) ='1') then
				SevenSegs <= toSevenSeg (2222);
				next_state <= start_selector;
			else
				SevenSegs <= toSevenSeg (2233);
				next_state <= mid_selector;
			end if;

		when mid_selector =>
			if(switches_in(1)='1') then
				SevenSegs <= toSevenSeg (3333);
				next_state <= mid_selector;
			else
				SevenSegs <= toSevenSeg (3344);
				next_state <= display_value;
			end if;

		when display_value => 
			if(switches_in(1) ='1') then
				SevenSegs <= toSevenSeg (4444);
				next_state <= display_value;
			else
				SevenSegs <= toSevenSeg (4455);
				next_state <= offer_prompt;
			end if;
			
		when offer_prompt => 
			if(switches_in(1)='1') then
				SevenSegs <= toSevenSeg (5555);
				next_state <= offer_prompt;
			else
				SevenSegs <= toSevenSeg (5511);
				next_state <= initiate;
			end if;
	end case;
end process;

end  fsm;

The objective of this code is to cycle through 5 states. Every time a push button is clicked it should move to the next state and display the new integer on the 7 segs in this order; 1111, 2222, 3333, 4444, 5555. The problem is however that the machine seems to skip to whatever state it wants. Sometimes 2222 goes to 4444 then back to 3333 then 1111. Anyone know what my problem here could be?
 

I have not testbenched it. I was not aware of anyway to do this. I will certainly look into that later today and see what I find. If it works like I think it might this could be very helpful.

Altera provide a free version of modelsim and Xilinx have the built in ISE simulator.

Oh yah wow. That does make sence... So the 'Uniform' statement is meant to genereate random input for a testbench? Is there anyway then to produce that randomly 'unsorted' array.

True randomness inside working code is not trivial to achieve. People can generate pseudo random numbers using a linear feedback shift register, but true randomness is a little bit harder to implement (you would need to understand the characteristics of your chip). You can use the uniform function to initialise variables (like you did) or constants because it is just run at elaboration time and wont map to any circuits, because it just ends up a fixed value.

Deffinatly true. Always been software and now have a circuits class that decided to skim over VHDL in the last few weeks.

Your VHDL is actually fairly well structured - it appears to have been taught fairly well or you have been reading good text books. But the important bit is the circuit design, not the code.

Just would have absolutely no idea on how to draw it out as a circuit.

I would try and get your head around the circuit before playing with loops. Loops unroll to parrallel (or serial, depending on what you're doing) hardware.


This is my feable attempt to turn an LED into a sort of blinking cursor. I want it to cycle on and off every 100000 clock cycles but now I realise that the clock has little to do with. So by async process you are refering to a process that doesnt detect clock events during it?

So would your sggection here be to make it its own process, counting when clk ='1'?

Thanks for the help!

Make it it's own process, with a "enable" generated from the async process. And no, although waiting for clk='1' may work in simulation, you'll actually find it possibly wont work on real hardware. You need to write it like your first process (if rising_edge(clk) then.....)



Moving on to your new code, you only wait until the button is pressed, and you probably hold it down way longer that a single clock. It will change state on every clock edge while the button is pressed, so its probably skipping thousands of states rather than just 1 or 2. You need to build a rising edge detector on your button:

Clue, you need 1 register and a comparator on the button input for this. Do not fall into the trap of many other beginners and use the switch as a clock.

Good Luck.
 

    V

    Points: 2
    Helpful Answer Positive Rating
True randomness inside working code is not trivial to achieve. People can generate pseudo random numbers using a linear feedback shift register, but true randomness is a little bit harder to implement (you would need to understand the characteristics of your chip). You can use the uniform function to initialise variables (like you did) or constants because it is just run at elaboration time and wont map to any circuits, because it just ends up a fixed value.

That makes sence. What about a process along these lines. Its certainly not truly random but i think it should be good enough for my application. Simply changes rand ever clock tick

Code:
SIGNAL seed1: natural;

SIGNAL seed2: natural;

process(rst,clk)
variable newCount : natural;

   begin
      if rst ='1' then
         count <= 0;
	seed1 <= 0;
	seed2 <= 0;

      elsif rising_edge(clk) then
	seed1 <= ( seed1 + 1 ) MOD 11;
	seed2 <= ( seed2 + 1 ) MOD 3;
	rand  <= ( seed1 + seed2 ) MOD 10;
      end if;
end process;

Make it it's own process, with a "enable" generated from the async process. And no, although waiting for clk='1' may work in simulation, you'll actually find it possibly wont work on real hardware. You need to write it like your first process (if rising_edge(clk) then.....)


Code:
PROCESS(rst, clk, highlitLED)
	constant max_count : natural := 48000000;
	variable count : natural range 0 to max_count;
	begin
        if blinkEnabled then
                if rst = '1' then
                	count := 0;
        		LEDs <= setLEDs(boxes);
        		LEDs(highlitLED) <= '1';

                elsif rising_edge(Clk) then
		        LEDs <= setLEDs(boxes);
        		if count < max_count/2 then
	        		LEDs(highlitLED)    <='1';
                        	count := count + 1;
		        elsif count < max_count then
			        LEDs(highlitLED)    <='0';
			        count := count + 1;
		        else
			        count := 0;
			        LEDs(highlitLED)    <='1';
                    	end if;
                end if;
    end if;
    end process;



Moving on to your new code, you only wait until the button is pressed, and you probably hold it down way longer that a single clock. It will change state on every clock edge while the button is pressed, so its probably skipping thousands of states rather than just 1 or 2. You need to build a rising edge detector on your button:

Clue, you need 1 register and a comparator on the button input for this. Do not fall into the trap of many other beginners and use the switch as a clock.

ahh yes that would make sence. How about :

Code:
SIGNAL pushbutton_edge : boolean;


process(rst,clk)
      variable detector : std_logic_vector (1 downto 0);
   begin
      if rst ='1' then
         detect := "00";


      elsif rising_edge(clk) then
         detector (1) := detector (0);
         detector (0) := pushbutton_in;
         
         pushbutton_edge = ( detector = "01")

      end if;
end process;

UPDATE: made chenges to my simple machine above anddddd it works! Now I finally have something to build off of. Thanks!

Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.math_real.all; 
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;

library work;
use work.mytypes.all; 

entity DealOrNoDeal is
    Port ( clk, rst : IN  STD_LOGIC;
           pushbutton_in	: in	std_logic_vector(number_of_push_buttons);
		   SevenSegs : out seven_seg_vector( number_of_seven_segs );
		   LEDs : out std_logic_vector( number_of_red_leds ));	
end DealOrNoDeal;

architecture fsm of DealOrNoDeal IS
	
    	function toSevenSeg ( num : NATURAL ) return seven_seg_vector is
		variable output: seven_seg_vector( number_of_seven_segs );
		constant sevSegKey : segArray := ("1000000", "1111001", "0100100", "0110000", "0011001",
		                                  "0010010", "0000011", "1111000", "0000000", "0011000");
		begin
		for I in number_of_seven_segs loop
			output(I) := sevSegKey((num / (10 ** I)) MOD 10);
		end loop;
		return output;
	end function toSevenSeg;
	
	TYPE state IS (initiate, start_selector, mid_selector, display_value, offer_prompt);
	SIGNAL present_state, next_state: STATE;
	SIGNAL pushbutton_edge : boolean_vector(number_of_push_buttons);
	
begin
				
process (clk,rst)
begin
	if (rst='1') then
		present_state <= initiate;
	elsif (rising_edge(clk)) then
		present_state <= next_state;   --state change.
end if;
end process;



process(rst,clk)
      variable detect : detector_vector(number_of_push_buttons);
   begin
      if rst ='1' then
		for i in number_of_push_buttons loop
			detect(i) := "00";
			pushbutton_edge(i) <= false;
		end loop;


      elsif rising_edge(clk) then
		for i in number_of_push_buttons loop
			detect(i)(1) := detect (i)(0);
			detect(i)(0) := pushbutton_in(i);
			
			pushbutton_edge(i) <= ( detect(i) = "10");
		end loop;
      end if;
end process;


--state machine process.
PROCESS(present_state, pushbutton_edge)
begin
	case present_state is
		when initiate =>
			if( not pushbutton_edge(1)) then
				SevenSegs <= toSevenSeg (1111);
				next_state <= initiate;
			else
				SevenSegs <= toSevenSeg (1122);
				next_state <= start_selector;
			end if;   

		when start_selector =>
			if( not pushbutton_edge(1)) then
				SevenSegs <= toSevenSeg (2222);
				next_state <= start_selector;
			else
				SevenSegs <= toSevenSeg (2233);
				next_state <= mid_selector;
			end if;

		when mid_selector =>
			if( not pushbutton_edge(1)) then
				SevenSegs <= toSevenSeg (3333);
				next_state <= mid_selector;
			else
				SevenSegs <= toSevenSeg (3344);
				next_state <= display_value;
			end if;

		when display_value => 
			if(not pushbutton_edge(1)) then
				SevenSegs <= toSevenSeg (4444);
				next_state <= display_value;
			else
				SevenSegs <= toSevenSeg (4455);
				next_state <= offer_prompt;
			end if;
			
		when offer_prompt => 
			if( not pushbutton_edge(1)) then
				SevenSegs <= toSevenSeg (5555);
				next_state <= offer_prompt;
			else
				SevenSegs <= toSevenSeg (5511);
				next_state <= initiate;
			end if;
	end case;
end process;

end  fsm;
 
Last edited:

I would NOT use mod operators in a real code. They build dividers that are unpipeline and so you will get a very slow maximum clock frequency (and timing problems if you try and clock it faster). you may have to look into putting pipelined dividers into the system if you insist on the dividers.

Otherwise, look into a linear feedback shift register (LFSR). Theres plenty of examples on google.
 

I got it to work! Really learned a lot in this thing. still not optimal but the transition to the synchronous variable changes really helped bring it together.

Code:
Library ieee;
use ieee.std_logic_1164.ALL;
use ieee.std_logic_arith.ALL;

PACKAGE mytypes IS 
			subtype number_of_seven_segs is integer range 0 to 3;
			subtype number_of_red_leds is integer range 9 downto 0;
			subtype number_of_push_buttons is integer range 3 downto 0;
			
			type segArray is array (0 to 9) of bit_vector(6 downto 0);
			TYPE state IS (initiate, start_selector, mid_selector, display_value, offer_prompt);
			type box_vector is array (natural range <>) of integer range 0 to 1000;
			type seven_seg_vector is array (natural range <>) of bit_vector(6 downto 0);
			type detector_vector is array (natural range <>) of std_logic_vector(1 downto 0);
			type boolean_vector is array (natural range <>) of boolean;
			type LED_vector is array (natural range <>) of std_logic_vector(number_of_red_leds);
END PACKAGE mytypes;
Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.math_real.all;

library work;
use work.mytypes.all;

entity DealOrNoDeal is
    Port ( clk, rst : IN  STD_LOGIC;
           pushbutton_in	: in	std_logic_vector(number_of_push_buttons);
		   SevenSegs : out seven_seg_vector( number_of_seven_segs );
		   LEDs : out std_logic_vector( number_of_red_leds ));
END DealOrNoDeal;

architecture fsm of DealOrNoDeal IS
	SIGNAL present_state, 			next_state: STATE;
	SIGNAL present_main_box_value,	next_main_box_value : integer RANGE 0 to 1000 := 0;
	SIGNAL present_open_box_value,	next_open_box_value : integer RANGE 0 to 1000 := 0;
	SIGNAL present_highlit_LED,		next_highlit_LED : integer RANGE 0 to 9 := 0;
	SIGNAL present_boxes,			next_boxes : box_vector(number_of_red_leds) := (OTHERS => 0);
	SIGNAL pushbutton_edge : boolean_vector(number_of_push_buttons);
	SIGNAL blinkEnable : boolean;

	function random ( max : NATURAL) return NATURAL is
		variable rand: real;
		variable s1 : positive := 1;
		variable s2 : positive := 1;
		BEGIN

		UNIFORM(s1, s2, rand);
		return (INTEGER(TRUNC(rand*1000.0)) MOD max);
	END function random;
	
    function toSevenSeg ( num : NATURAL ) return seven_seg_vector is
		variable output: seven_seg_vector( number_of_seven_segs );
		constant sevSegKey : segArray := ("1000000", "1111001", "0100100", "0110000", "0011001",
		                                  "0010010", "0000011", "1111000", "0000000", "0011000");
		BEGIN
		for I in number_of_seven_segs LOOP
			output(I) := sevSegKey((num / (10 ** I)) MOD 10);
		END LOOP;
		return output;
	END function toSevenSeg;

	function toLogic ( num : NATURAL ) return STD_LOGIC is
		BEGIN
			IF(num = 0 ) THEN
				RETURN '0';
			END IF;
			RETURN '1';
	END function toLogic;

	function setLEDs(key : box_vector) return std_logic_vector is
		variable output:std_logic_vector( number_of_red_leds );
		BEGIN
			FOR I IN number_of_red_leds LOOP
				output(I) := toLogic (key(I));
			END LOOP;
			return output;
	END function setLEDs;

	function setBoxes return box_vector is
		variable boxValKey : box_vector ( number_of_red_leds ) := (1, 5, 10, 25, 50, 75, 100, 500, 750, 1000);
		variable result : box_vector ( number_of_red_leds );
		variable rand : NATURAL;
		BEGIN
			rand := random (10);
			FOR I IN number_of_red_leds LOOP
				while ( boxValKey( rand ) = 0 ) LOOP
					rand := (rand + 3) MOD 10;
				END LOOP;
				result(I) := boxValKey( rand );
				boxValKey(rand) := 0;
				rand := random (10);
			END LOOP;
		return result;
	END function setBoxes;

	function getOffer(key : box_vector; startsum : NATURAL) return POSITIVE is
		variable num : NATURAL := 1;
		variable sum : NATURAL := startsum;
		BEGIN
			FOR I IN number_of_red_leds LOOP
				IF(key(I) /= 0) THEN
					sum := sum + key(I);
				    num := num + 1;
				END IF;
			END LOOP;
			sum := sum / num;
			return sum;
	END function getOffer;

BEGIN

process (clk,rst)
BEGIN
	IF (rst='1') THEN
		present_state <= initiate;
		present_main_box_value <= 0;
		present_open_box_value <= 0;
		present_highlit_LED <= 0;
		present_boxes <= (OTHERS => 0);
	ELSIF (rising_edge(clk)) THEN
		present_state <= next_state;
		present_main_box_value <= next_main_box_value;
		present_open_box_value <= next_open_box_value;
		present_highlit_LED <= next_highlit_LED;
		present_boxes <= next_boxes;
END IF;
END process;

PROCESS(rst, clk, present_highlit_LED, present_boxes)
	constant max_count : natural := 48000000;
	variable count : natural RANGE 0 to max_count;
	BEGIN
        IF rst = '1' THEN
        	count := 0;
			LEDs <= (OTHERS => '1');

        ELSIF rising_edge(Clk) THEN
			IF blinkEnable = true THEN
				IF count < max_count/2 THEN
					LEDs <= (OTHERS => '0');
					LEDs(present_highlit_LED) <='1';
					count := count + 1;
				ELSIF count < max_count THEN
					LEDs <= setLEDs(present_boxes);
					count := count + 1;
				ELSE
					count := 0;
					LEDs <= (OTHERS => '0');
					LEDs(present_highlit_LED) <='1';
				END IF;
			ELSE
				count := 0;
				LEDs <= (OTHERS => '0');
			END IF;
        END IF;
END process;

PROCESS(pushbutton_edge, present_highlit_LED)
	BEGIN
		IF (pushbutton_edge(3) XOR pushbutton_edge(2)) THEN
			IF(pushbutton_edge(3)) THEN
				next_highlit_LED <= (present_highlit_LED + 1) MOD 10;
			ELSE
				next_highlit_LED <= (present_highlit_LED - 1) MOD 10;
			END IF;
		ELSE
			next_highlit_LED <= present_highlit_LED;
		END IF;
END process;

process(rst,clk)
      variable detect : detector_vector(number_of_push_buttons);
   BEGIN
      IF rst ='1' THEN
		for i in number_of_push_buttons LOOP
			detect(i) := "00";
			pushbutton_edge(i) <= false;
		END LOOP;


      ELSIF rising_edge(clk) THEN
		for i in number_of_push_buttons LOOP
			detect(i)(1) := detect (i)(0);
			detect(i)(0) := pushbutton_in(i);

			pushbutton_edge(i) <= ( detect(i) = "10");
		END LOOP;
      END IF;
END process;

PROCESS(present_state, present_main_box_value,present_open_box_value, present_boxes, present_highlit_LED, pushbutton_edge)
BEGIN
	CASE present_state is
		WHEN initiate =>
			SevenSegs <= toSevenSeg (present_main_box_value);
			next_open_box_value <= 0;
			next_main_box_value <= present_main_box_value;
			next_boxes <= setboxes;
			blinkEnable <= false;
			IF(pushbutton_edge(1)) THEN
				next_state <= start_selector;
			ELSE
				next_state <= initiate;
			END IF;

		WHEN start_selector =>
			next_open_box_value <= 0;
			next_boxes <= present_boxes;
			blinkEnable <= true;
			SevenSegs <= toSevenSeg (5555);
			IF(pushbutton_edge(1)) THEN
				next_state <= mid_selector;
				next_main_box_value <= present_boxes(present_highlit_LED);
				next_boxes(present_highlit_LED) <= 0;
			ELSE
				next_state <= start_selector;
				next_main_box_value <= 0;
			END IF;

		WHEN mid_selector =>
			next_boxes <= present_boxes;
			next_main_box_value <= present_main_box_value;
			blinkEnable <= true;
			IF(pushbutton_edge(1) AND present_boxes(present_highlit_LED) /= 0) THEN
				SevenSegs <= toSevenSeg (3344);
				next_state <= display_value;
				next_open_box_value <= present_boxes(present_highlit_LED);
				next_boxes(present_highlit_LED) <= 0;
			ELSE
				SevenSegs <= toSevenSeg (3333);
				next_state <= mid_selector;
				next_open_box_value <= 0;
			END IF;

		WHEN display_value =>
			next_main_box_value <= present_main_box_value;
			next_open_box_value <= present_open_box_value;
			SevenSegs <= toSevenSeg (present_open_box_value);
			blinkEnable <= false;
			IF(pushbutton_edge(1)) THEN
				next_state <= offer_prompt;
			ELSE
				next_state <= display_value;
			END IF;
			next_boxes <= present_boxes;

		WHEN offer_prompt =>
			blinkEnable <= false;
			next_main_box_value <= present_main_box_value;
			next_open_box_value <= 0;
			SevenSegs <= toSevenSeg (getOffer(present_boxes, present_main_box_value));
			IF(pushbutton_edge(1)) THEN
				next_state <= initiate;
			ELSIF(pushbutton_edge(0)) THEN
				next_state <= mid_selector;
			ELSE
				next_state <= offer_prompt;
			END IF;
			next_boxes <= present_boxes;
	END CASE;
END process;

END  fsm;

Thanks!!
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top