Continuous Queue in VHDL?

Discussion in 'VHDL' started by dcwang3, Nov 13, 2009.

  1. dcwang3

    dcwang3

    Joined:
    Nov 13, 2009
    Messages:
    8
    Hey guys:

    I'm trying to work on a code in VHDL that basically has a queue. I want the queue to retrieve data continuously. So basically once the queue is full, it will start to write over the old data (in the last spots). I would like to have pointers to tell me where the first and the last entry, and if there is a wrapback, to be able to keep those pointers synced and correct.

    I guess I am having a hard time trying to figure out how to keep track of the pointers.

    Can another give me some pointers or advice?

    Thanks
     
    dcwang3, Nov 13, 2009
    #1
    1. Advertising

  2. dcwang3

    jeppe

    Joined:
    Mar 10, 2008
    Messages:
    348
    Location:
    Denmark
    Take a look at this post: Must be what your looking for.

    velocityreviews.com/forums/t703373-representing-the-buffer-with-logic-gates-flipflops.html
    (copy the address to the browser) or look below your post in this group
     
    jeppe, Nov 13, 2009
    #2
    1. Advertising

  3. dcwang3

    dcwang3

    Joined:
    Nov 13, 2009
    Messages:
    8
    I looked at it and I am getting some ideas. I have written code. I am trying to make a generic code, so that I have generic variables at the top and can change the width and size of my QUEUE.

    for instance:

    Code:
    ENTITY FIFO IS
    	GENERIC(	SIZE:	INTEGER:= 16;
    				WIDE:	INTEGER:= 4
    		   );
    	PORT( 
    	           CLK,RESET,WRITE_EN,READ_EN:	IN STD_LOGIC;
                       DATA_IN: 	IN  STD_LOGIC_VECTOR(WIDE-1 DOWNTO 0);
    		   DATA_OUT:  OUT   STD_LOGIC_VECTOR(WIDE-1 DOWNTO 0);
         		   QUEUE_EMPTY,QUEUE_FULL:   OUT  STD_LOGIC
    	    );
    END FIFO;
    
    ARCHITECTURE BEHAVIOR OF FIFO IS
    
    COMPONENT QUEUE_ARRAY 
    	PORT(	WRITE_EN,CLK:	IN	STD_LOGIC;
    			DATA_IN:	IN	STD_LOGIC_VECTOR(WIDE-1 DOWNTO 0);
    			DATA_OUT:	IN	STD_LOGIC_VECTOR(WIDE-1 DOWNTO 0);
    			ADDR:		IN	STD_LOGIC_VECTOR(CONV_STD_LOGIC(SIZE,4))
    		);
    END COMPONENT;

    I don't think I am doing it correctly.

    LIke I want ADDR signal in the component QUEUE_ARRAY be std_logic_vector in the code, but want to initialize it with an integer, so I can easily change it.

    Any suggestions?

    Thanks
     
    dcwang3, Nov 17, 2009
    #3
  4. dcwang3

    jeppe

    Joined:
    Mar 10, 2008
    Messages:
    348
    Location:
    Denmark
    This will be a more correct start of your code.
    You must use the conversion function inside QUEUE_ARRAY.

    Code:
    ENTITY FIFO IS
    	GENERIC(	SIZE:	INTEGER:= 16;
    				WIDE:	INTEGER:= 4
    		   );
    	PORT( 
    	           CLK,RESET,WRITE_EN,READ_EN:	IN STD_LOGIC;
                       DATA_IN: 	IN  STD_LOGIC_VECTOR(WIDE-1 DOWNTO 0);
    		   DATA_OUT:  OUT   STD_LOGIC_VECTOR(WIDE-1 DOWNTO 0);
         		   QUEUE_EMPTY,QUEUE_FULL:   OUT  STD_LOGIC
    	    );
    END FIFO;
    
    ARCHITECTURE BEHAVIOR OF FIFO IS
    
    COMPONENT QUEUE_ARRAY 
    	PORT(	WRITE_EN,CLK:	IN	STD_LOGIC;
    			DATA_IN:	IN	STD_LOGIC_VECTOR(WIDE-1 DOWNTO 0);
    			DATA_OUT:	[B][COLOR="Red"]OUT[/COLOR][/B]	STD_LOGIC_VECTOR(WIDE-1 DOWNTO 0);
    			ADDR:		IN	STD_LOGIC_VECTOR(2**SIZE-1 DOWNTO 0);
    END COMPONENT; 
     
    jeppe, Nov 17, 2009
    #4
  5. dcwang3

    dcwang3

    Joined:
    Nov 13, 2009
    Messages:
    8
    what exactly does the 2**WIDE-1. Obviously it should turn out to be 3. What does ** do?

    Thanks
     
    dcwang3, Nov 17, 2009
    #5
  6. dcwang3

    jeppe

    Joined:
    Mar 10, 2008
    Messages:
    348
    Location:
    Denmark
    2**1 = 2
    2**2 = 4
    2**3 = 8 and so on ** means power of
    2**4 = 16
    so 2**SIZE-1 actually 15

    UPS - sorry should be (SIZE-1 DOWNTO 0) in the code
     
    Last edited: Nov 17, 2009
    jeppe, Nov 17, 2009
    #6
  7. dcwang3

    dcwang3

    Joined:
    Nov 13, 2009
    Messages:
    8
    I need some help trying to figure out what is wrong with my code. I'm trying to make a continuous queue that will put data in until it is full, and then once it is full, it will overwrite the old data. I need a pointer at the start and the end of the queue. Can someone help me?

    Code:
    LIbrary IEEE;
    use IEEE.std_logic_1164.all;
    use IEEE.std_logic_arith.all;
    use IEEE.std_logic_unsigned.all;
    
    ENTITY FIFO_TEST IS
    --	GENERIC(	SIZE:	INTEGER:= 16;
    --				WIDE:	INTEGER:= 4
    --		   );
    	PORT( 
    			CLK,RESET,WRITE_EN,READ_EN:		IN	STD_LOGIC;
    		    DATA_IN: 						IN	STD_LOGIC_VECTOR(3 DOWNTO 0);
    		    DATA_OUT: 						OUT	STD_LOGIC_VECTOR(3 DOWNTO 0);
         		ARRAY_COUNT:					OUT	STD_LOGIC_VECTOR(2 DOWNTO 0);
         		QUEUE_EMPTY,QUEUE_FULL:			OUT	STD_LOGIC;
    			WRAP:							BUFFER	STD_LOGIC
    	    );
    END FIFO_TEST;
    
    ARCHITECTURE BEHAVIOR OF FIFO_TEST IS
    
    COMPONENT QUEUE_ARRAY 
    	PORT(	WRITE_EN,CLK:	IN	STD_LOGIC;
    			DATA_IN:	IN	STD_LOGIC_VECTOR(3 DOWNTO 0);
    			DATA_OUT:	OUT	STD_LOGIC_VECTOR(3 DOWNTO 0);
    			ADDR:		IN	STD_LOGIC_VECTOR(2 DOWNTO 0)
    		);
    END COMPONENT;
    
    SIGNAL START_POINTER:	STD_LOGIC_VECTOR(2 DOWNTO 0);
    SIGNAL END_POINTER:		STD_LOGIC_VECTOR(2 DOWNTO 0);
    SIGNAL COUNTER:			STD_LOGIC_VECTOR(2 DOWNTO 0);
    SIGNAL WRITE_ENABLE_S:	STD_LOGIC;
    SIGNAL ADDR_S:			STD_LOGIC_VECTOR(2 DOWNTO 0);
    --SIGNAL WRAP:			STD_LOGIC;
    SIGNAL QUEUE_FULL_S:	STD_LOGIC;
    SIGNAL QUEUE_EMPTY_S:	STD_LOGIC;
    
    BEGIN
    
        FifoRam : QUEUE_ARRAY
    		PORT MAP(
    					WRITE_EN    =>  WRITE_ENABLE_S,
    					CLK         =>  CLK,
                        DATA_IN     =>  DATA_IN,
                        DATA_OUT    =>  DATA_OUT,
    					ADDR        =>  START_POINTER
    				);
    	
    	PROCESS(CLK,RESET)
    	BEGIN
    		IF (RESET = '1') THEN
    			START_POINTER <= (OTHERS=>'0');
    			END_POINTER <= (OTHERS=>'0');
    			COUNTER  <= (OTHERS=>'0');
    		ELSIF(RISING_EDGE(CLK)) THEN
    			IF(WRITE_EN = '1' AND WRAP = '0' AND READ_EN = '0') THEN				
    				IF(COUNTER = "11111111") THEN
    					START_POINTER <= (OTHERS => '0');
    					END_POINTER <= END_POINTER + 1;
    					WRAP <= '1';
    				ELSE
    					START_POINTER <= START_POINTER + 1;
    					COUNTER <= COUNTER + 1;
    				END IF;
    			END IF;
    			
    			IF(WRITE_EN = '1' AND WRAP ='1' AND READ_EN ='0') THEN
    				IF(END_POINTER = "11111111") THEN
    					END_POINTER <= (OTHERS => '0');	
    				ELSIF(START_POINTER = "11111111") THEN
    					START_POINTER <= (OTHERS =>'0');
    				ELSE
    					START_POINTER <= START_POINTER + 1;
    					END_POINTER <= END_POINTER + 1;
    				END IF;				
    			END IF;
    
    			IF(READ_EN = '1' AND WRITE_EN ='0') THEN	
    				IF(START_POINTER = END_POINTER) THEN
    					QUEUE_EMPTY_S <= '1';
    				ELSE
    					START_POINTER <= START_POINTER - 1;
    					COUNTER <= COUNTER - 1;
    				END IF;
    				
    				IF(COUNTER = 0) THEN
    					QUEUE_EMPTY_S <= '1';
    				ELSE
    					QUEUE_EMPTY_S <= '0';
    				END IF;
    			END IF;				
    		END IF;
    	END PROCESS;
    -----------------------------------------------------------
    --  Combinatorial Logic
    -----------------------------------------------------------
    	ARRAY_COUNT <= COUNTER;
    	
    	WRAP <= '1' WHEN (COUNTER = "11111111") ELSE '0';
    
    	QUEUE_FULL <= '1' WHEN  (COUNTER = "11111111") ELSE '0';
    	QUEUE_EMPTY <= QUEUE_EMPTY_S;
    
    	WRITE_ENABLE_S <= '1' WHEN (WRITE_EN = '1') ELSE '0';
    	
    	
    
    ------------------------------------------------------------
    END BEHAVIOR;

    Code:
    Library IEEE;
    use IEEE.std_logic_1164.all;
    use IEEE.std_logic_arith.all;
    use IEEE.std_logic_unsigned.all;
    
    
    ENTITY QUEUE_ARRAY IS
    	GENERIC(	LEN:	INTEGER:= 16;
    				WIDE:	INTEGER:= 4
    		   );
    			
    	PORT(	WRITE_EN,CLK:	IN	STD_LOGIC;
    			DATA_IN:		IN	STD_LOGIC_VECTOR(3 DOWNTO 0);
    			DATA_OUT:		OUT	STD_LOGIC_VECTOR(3 DOWNTO 0);
    			ADDR:			IN	STD_LOGIC_VECTOR(2 DOWNTO 0)
    		);
    END QUEUE_ARRAY;
    
    ARCHITECTURE BEHAVIOR OF QUEUE_ARRAY IS
    	TYPE QUEUE_SIZE IS ARRAY(7 DOWNTO 0) OF STD_LOGIC_VECTOR(3 DOWNTO 0);
    	SIGNAL QUEUE_ARRAY: QUEUE_SIZE;
    
    BEGIN
    	
    PROCESS(CLK,QUEUE_ARRAY,ADDR)
    BEGIN
    	IF(RISING_EDGE(CLK)) THEN
    		IF(WRITE_EN = '1') THEN
    			QUEUE_ARRAY(CONV_INTEGER(ADDR)) <= DATA_IN;
    		END IF;
    	END IF;
    
    DATA_OUT <= QUEUE_ARRAY(CONV_INTEGER(ADDR));
    
    END PROCESS;
    
    END BEHAVIOR;
     
    Last edited: Nov 18, 2009
    dcwang3, Nov 18, 2009
    #7
  8. dcwang3

    jeppe

    Joined:
    Mar 10, 2008
    Messages:
    348
    Location:
    Denmark
    First must you realise - its not possible to drive the signal "WRAP" from both a process and from concurrent code.
    Besides do you not need this I believe, as a VECTOR<= VECTOR+1 will wrap around automaticly.

    Your code also miss a way to select among the START_POINTER and the END_POINTER. It seems that the START_POINTER connected permanently to the QUEUE_ARRAY.

    My version would look like this (but OK - the RAM must be a DUAL-PORT type)

    Code:
    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    use IEEE.STD_LOGIC_ARITH.ALL;
    use IEEE.STD_LOGIC_UNSIGNED.ALL;
    
    entity FIFO_TEST2 is
          generic (
                B : natural :=8; -- number of bit
                W: natural :=4 -- number of address bit
                );
          port ( clk, reset : in std_logic;
                 rd, wr : in std_logic;
                 w_data : in std_logic_vector ( B-1 downto 0);
                 empty, full : inout std_logic;
                 r_data : out std_logic_vector (B-1 downto 0));
    end FIFO_TEST2;
    
    architecture Behavioral of FIFO_TEST2 is
       type array_type is array (0 to 2**W-1) of std_logic_vector( B-1 downto 0);
       signal ringbuffer: array_type;
       signal w_index, r_index: std_logic_vector( W-1 downto 0);  --integer range 0 to 2**W-1;
       signal count:            std_logic_vector( W downto 0);
    begin
    
       empty <= '1' when count=0    else '0';
       full  <= '1' when count=2**W else '0';
       r_data <= ringbuffer( conv_integer(r_index));
       
       process( clk)
          variable wr_edge, rd_edge: std_logic_vector( 1 downto 0) := "00";
       begin
          if rising_edge( clk) then
             if reset = '1' then
                w_index <= (others=>'0');
                r_index <= (others=>'0');
                count   <= (others=>'0');
                wr_edge := wr&wr;
                rd_edge := rd&rd;
             else
                if wr_edge="01" then 
                   ringbuffer( conv_integer(w_index)) <= w_data;
                   w_index <= w_index+1;
                   if full='0' then
                      count   <= count+1;
                   else
                      r_index <= r_index + 1; -- Remove oldest data
                   end if;
                end if;
                if rd_edge="01" and empty='0' then
                   r_index <= r_index+1;
                   count <= count-1;
                end if;
                wr_edge := wr_edge(0) & wr;
                rd_edge := rd_edge(0) & rd;
             end if;
          end if;
       end process;
    end Behavioral;
     
    jeppe, Nov 18, 2009
    #8
  9. dcwang3

    dcwang3

    Joined:
    Nov 13, 2009
    Messages:
    8
    I updated the code probably after you looked at it initially.

    But the way I was trying to write my code was, that I would have a QUEUE of a a certain size (ie 16 entries). Then I would write continuously. If I write all the way up to the 16th entry and WRITE_EN is still '1', it would go back to the first entry and start filling over the old data.

    I have the START_POINTER to point to the newest entry, and END_POINTER to the last old entry. I have the WRAP signal to fulfill the condition of if START = END. So in the beginning when it starts, I just want to increment the START_POINTER until it gets to the last entry, and if it fills up that 16th entry, for START_POINTER to go back to the first entry, and then END_POINTER increments to the second entry (because that is the oldest data entry).

    I hope I am explaining it correctly?

    I'll look over your code tonight and see how it works. Thanks for the help
     
    dcwang3, Nov 19, 2009
    #9
  10. dcwang3

    dcwang3

    Joined:
    Nov 13, 2009
    Messages:
    8
    I'm looking at the code, what is the wr_edge and rd_edge for? especially in the reset part, with wr_edge:=wr&wr ; rd_edge:=rd&rd
     
    dcwang3, Nov 19, 2009
    #10
  11. dcwang3

    jeppe

    Joined:
    Mar 10, 2008
    Messages:
    348
    Location:
    Denmark
    In order to detect edges at WR and RD do I use 2-bit shiftregisters.

    -----_____------
    1 1 1 0 0 0 1 1 1

    Wr_edge <= Wr & Wr; --means that both bits Wr_edge(1) and Wr_edge(0) will get the same value 11 or 00
    Wr_edge <= Wr_edge(0) & Wr; -- Will shift Wr_edge(0) to Wr_edge(1) and put the new Wr value at Wr_edge(0).

    A positive edge will then result in Wr_edge = "01"
     
    jeppe, Nov 19, 2009
    #11
  12. dcwang3

    dcwang3

    Joined:
    Nov 13, 2009
    Messages:
    8
    what is the point of having a variable rather than just using signals declared in the architecture for RD and WR?

    I have not used variables before. Does the wr_edge and rd_edge also initialize to "00" at the beginning of the process, and changes whenever it appears within the process?
     
    dcwang3, Nov 19, 2009
    #12
  13. dcwang3

    jeppe

    Joined:
    Mar 10, 2008
    Messages:
    348
    Location:
    Denmark
    what is the point of having a variable rather than just using signals declared in the architecture for RD and WR?
    Your right - they could/should be signals instead. In some cases could variables give more readable code, but this not the case.
    Just an old habbit of mine :)

    Does the wr_edge and rd_edge also initialize to "00" at the beginning of the process, and changes whenever it appears within the process?

    There will be no difference - but if you place the WR_edge := WR_edge(0)&Wr in front will the synthesize give you a poor result :(
    They will initialize to "00" or reset to WR&WR
     
    jeppe, Nov 19, 2009
    #13
  14. dcwang3

    dcwang3

    Joined:
    Nov 13, 2009
    Messages:
    8
    hmmm. thanks. I appreciate all the help, I understand now.
     
    dcwang3, Nov 19, 2009
    #14
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Paul L. Du Bois

    Queue.Queue-like class without the busy-wait

    Paul L. Du Bois, Mar 24, 2005, in forum: Python
    Replies:
    29
    Views:
    1,079
    Antoon Pardon
    Apr 4, 2005
  2. Russell Warren

    Is Queue.Queue.queue.clear() thread-safe?

    Russell Warren, Jun 22, 2006, in forum: Python
    Replies:
    4
    Views:
    702
    Russell Warren
    Jun 27, 2006
  3. Kceiw
    Replies:
    3
    Views:
    1,017
    Jim Langston
    Mar 14, 2006
  4. Gabriel Rossetti
    Replies:
    3
    Views:
    577
    Jerry Hill
    Apr 25, 2008
  5. Kris
    Replies:
    0
    Views:
    504
Loading...

Share This Page