---------------------------------------------------------------------------------- -- Company: University of Freiburg -- Engineer: Tom Barber (tom.barber@cern.ch) -- -- Create Date: 13:12:21 03/09/2011 -- Design Name: -- Module Name: hawaiiFIFO - Behavioral -- Project Name: ATLAS Strips Upgrade HSIO -- Target Devices: -- Tool versions: ISE 13.4 -- Description: Was a generic FIFO, now shift register with occupancy -- -- * The FIFO can hold 2**depth std_logic values. -- * It can be read out with variable length. -- * An occupancy counter takes care of the full/empty flags -- ** if full: write is ignored -- ** if empty: read is ignored -- * Last item written is found at address 0 -- -- Dependencies: None -- -- Revision: -- Revision 0.01 - File Created -- Revision 0.02 - Bruce Gallop changed from FIFO to shift register (to remove address lookup logic) -- Additional Comments: -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.all; use IEEE.NUMERIC_STD.all; entity hawaiiFIFO is generic ( depth : natural := 4 -- fifo will be 2**depth bits deep ); port ( clock, reset : in std_logic; -- clock and reset rd, wr : in std_logic; -- read / write enable (are these needed) -- Length in bits of read read_length : in std_logic_vector(depth-1 downto 0); -- Read and Write data: must be maximum length of buffer -- as the rw length can be changed during running write_data : in std_logic; read_data : out std_logic_vector(2**depth-1 downto 0); -- Buffer occupancy and full/empty flags occupancy : out std_logic_vector(depth downto 0); full, empty : out std_logic ); end hawaiiFIFO; architecture Behavioral of hawaiiFIFO is -- What is the maximum occupancy constant max_occupancy : integer := 2**depth; -- The shift register itself -- Could be expanded as an array of vectors if required? signal array_reg : std_logic_vector(max_occupancy-1 downto 0); -- Status signals signal full_reg, empty_reg : std_logic := '0'; signal wr_op, full_and_empty : std_logic_vector(1 downto 0); signal wr_en : std_logic; -- Internal occupancy and length signals -- as integers (arithmatic is easier) signal occupancy_internal, occupancy_next, read_length_internal : integer range 0 to max_occupancy; begin -------------------------------------------------------- -- Write data to register from input -------------------------------------------------------- process(clock, reset) begin if (clock'event and clock = '1') then -- rising clock if (reset = '1') then -- Reset all of the FIFO values array_reg <= (others => '0'); else -- Only output if writing is enabled if (wr_en = '1') then -- Write input at index 0 and shift remainder array_reg <= array_reg(max_occupancy-2 downto 0) & write_data; end if; end if; end if; end process; -- Output -- Always output something process (array_reg, reset) begin if (reset = '1') then read_data <= (others => '0'); else read_data <= array_reg; end if; end process; -------------------------------------------------------- -- Write enable if FIFO is not full -------------------------------------------------------- wr_en <= wr and (not full_reg); -------------------------------------------------------- -- FIFO control Logic -------------------------------------------------------- -- Register for read and write pointers process(clock, reset) begin if (clock'event and clock = '1') then if (reset = '1') then -- reset all signals occupancy_internal <= 0; else occupancy_internal <= occupancy_next; end if; end if; end process; ------------------------------------------------------------ -- Successive pointer values ------------------------------------------------------------ -- Convert external signals to internal integers read_length_internal <= to_integer( unsigned(read_length) ); -- This checks the occupancy and the length of -- read/write to see if the buffer is full or empty process(occupancy_internal, read_length_internal) begin -- Make sure the occupancy is large enough to read out -- a chunk of data read_length bits long if (occupancy_internal < read_length_internal) then empty_reg <= '1'; else empty_reg <= '0'; end if; -- Also, make sure the buffer is empty enough to write -- a chunk of data write_length (constant 1) bits long if ( (max_occupancy - occupancy_internal) < 1 ) then full_reg <= '1'; else full_reg <= '0'; end if; end process; -- Next-state logic wr_op <= wr & rd; -- Read and write strobed together full_and_empty <= full_reg & empty_reg; process(wr_op, full_and_empty, empty_reg, rd, wr, occupancy_internal, read_length_internal, full_reg) begin occupancy_next <= occupancy_internal; -- If we are reading AND writing, and are neither full nor -- empty, then increment both pointers, and update BOTH occupancies if (( wr_op = "11" ) and ( full_and_empty = "00" ) ) then -- Need some additional checks in case we get a negative number if ((occupancy_internal + 1) >= read_length_internal) then occupancy_next <= occupancy_internal - read_length_internal + 1; end if; -- Just read elsif (( rd = '1' ) and ( empty_reg /= '1')) then if (occupancy_internal >= read_length_internal) then occupancy_next <= occupancy_internal - read_length_internal; end if; -- Just Write elsif (( wr = '1' ) and ( full_reg /= '1' )) then occupancy_next <= occupancy_internal + 1; end if; end process; -- Output full <= full_reg; empty <= empty_reg; occupancy <= std_logic_vector( to_unsigned(occupancy_internal, occupancy'length) ); end Behavioral;