---------------------------------------------------------------------------------- -- Company: University of Freiburg -- Engineer: Tom Barber (thomas.barber@physik.uni-freiburg) -- -- Create Date: 10:29:58 03/21/2011 -- Design Name: Strips upgrade histogramming -- Module Name: histogrammer - Behavioral -- Project Name: -- Target Devices: -- Tool versions: -- Description: -- This should serve as a general histogrammer, implemented as a four-state FSM. -- (Perhaps this is overkill?) I couldn't get it to work with a simpler model... -- Histogram waits to recieve a write signal, after which it reads the current -- value n of the current address in RAM. On the next clock, it moves to write -- to write a value of n+1, before returning to idle. -- -- I think at the moment it requires a 2 clock latency to do this (ie, can't have -- two writes in successive ticks (they will be ignored). -- -- If read mode is enabled, the histogrammer strobes the output address to the -- requested output, vetoing any write operations that may occur. -- This has a latency of 1 clock tick, so the output will appear 1 tick after -- requested. -- -- On the clock tick following readout, the previous bin is also zeroed -- (maybe have a switch for this eventually?) -- -- Dependencies: -- Needs the Xilinx core generator to create a Dual Block RAM Core -- -- Revision: -- Revision 0.01 - File Created -- Additional Comments: -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.all; use IEEE.NUMERIC_STD.all; entity histogrammer is generic ( -- These cannot be changed once the core has -- been generated! -- If the core is regenerated with different -- values, these need to be changed too... -- Would be nice to specify generics for this, but -- I think it is fixed in the core histogram_depth : natural := 11; histogram_width : natural := 16; max_address_count : natural := 1280 ); port ( clock, reset : in std_logic; -- clock and reset inputAddress : in std_logic_vector(histogram_depth-1 downto 0); -- read address writeEnable : in std_logic; -- when to increment the buffer readEnable : in std_logic; -- readout outputAddress : in std_logic_vector(histogram_depth-1 downto 0); -- readout address histogram_occupancy : out std_logic_vector(histogram_width-1 downto 0) -- histogrammed value ); end histogrammer; architecture Behavioral of histogrammer is -- define the states of histogram FSM type state_type is ( idle, -- wait read_bin, -- read n write_bin, -- write n+1 read_out -- readout address (veto writing) ); signal next_state, current_state : state_type; component histogram port ( clka : in std_logic; wea : in std_logic_vector(0 downto 0); addra : in std_logic_vector(histogram_depth-1 downto 0); dina : in std_logic_vector(histogram_width-1 downto 0); douta : out std_logic_vector(histogram_width-1 downto 0); clkb : in std_logic; web : in std_logic_vector(0 downto 0); addrb : in std_logic_vector(histogram_depth-1 downto 0); dinb : in std_logic_vector(histogram_width-1 downto 0); doutb : out std_logic_vector(histogram_width-1 downto 0)); end component; signal bin_occupancy, bin_occupancy_next, bin_occupancy_incr : integer range 0 to 2**histogram_width-1 := 0; signal bin_occupancy_bits, bin_occupancy_bits_next : std_logic_vector(histogram_width-1 downto 0) := (others => '0'); signal input_address_integer, output_address_integer : integer range 0 to 2**histogram_width-1; signal internal_input_address, internal_output_address, internal_input_address_cut, internal_output_address_cut, internal_output_address_last : std_logic_vector(histogram_depth-1 downto 0); signal internal_write_enable : std_logic := '0'; begin histoMem : histogram port map( addra => internal_input_address, -- use a to write addrb => internal_output_address, -- use b to read clka => clock, clkb => clock, dina => bin_occupancy_bits_next, -- write occupancy dinb => "0000000000000000", douta => open, doutb => bin_occupancy_bits, -- read occupancy wea(0) => internal_write_enable, -- write enable web => "0" -- never write using b ); bin_occupancy <= to_integer( unsigned(bin_occupancy_bits)); input_address_integer <= to_integer( unsigned(inputAddress) ); output_address_integer <= to_integer( unsigned(outputAddress) ); histogram_occupancy <= bin_occupancy_bits; internal_output_address <= internal_input_address_cut(histogram_depth-1 downto 0) when (current_state = read_bin) else internal_output_address_cut(histogram_depth-1 downto 0); internal_output_address_cut <= std_logic_vector( to_unsigned(output_address_integer, internal_output_address_cut'length)) when (output_address_integer < max_address_count) else (others => '0'); internal_input_address_cut <= std_logic_vector( to_unsigned(input_address_integer, internal_input_address_cut'length)) when (input_address_integer < max_address_count) else (others => '0'); process(reset, clock) is begin if rising_edge(clock) then if (reset = '1') then current_state <= idle; internal_output_address_last <= (others => '0'); else -- move the state on every clock tick current_state <= next_state; -- need to buffer the output address so it can be cleared -- on the next clock internal_output_address_last <= internal_output_address_cut; case current_state is when idle => internal_input_address <= (others => '0'); internal_write_enable <= '0'; bin_occupancy_bits_next <= (others => '0'); when read_bin => internal_input_address <= internal_input_address_cut(histogram_depth-1 downto 0); internal_write_enable <= '0'; bin_occupancy_bits_next <= (others => '0'); when write_bin => internal_write_enable <= '1'; bin_occupancy_bits_next <= std_logic_vector( to_unsigned(bin_occupancy + 1, histogram_width)); when read_out => -- Also start to zero bins that have already been read out internal_write_enable <= '1'; bin_occupancy_bits_next <= (others => '0'); internal_input_address <= internal_output_address_last; when others => end case; end if; end if; end process; state_logic : process(current_state, readEnable, writeEnable, input_address_integer, output_address_integer, internal_output_address_last) begin case current_state is when idle => if ((readEnable = '1') and (output_address_integer < max_address_count)) then next_state <= read_out; elsif ((writeEnable = '1') and (input_address_integer < max_address_count)) then -- Read the bin first next_state <= read_bin; else next_state <= idle; end if; when read_bin => -- Now write it next_state <= write_bin; when write_bin => next_state <= idle; when read_out => -- Continue readout until the input pin goes low if ((readEnable = '1') and (output_address_integer < max_address_count)) then next_state <= read_out; else next_state <= idle; end if; when others => next_state <= idle; end case; end process; -- read_write: process(current_state, output_address_integer) -- begin -- -- -- if (rising_edge(clock)) then -- -- case current_state is -- -- when idle => -- internal_input_address <= (others => '0'); -- internal_output_address <= (others => '0'); -- internal_write_enable <= '0'; -- bin_occupancy_bits_next <= (others => '0'); -- histogram_occupancy <= (others => '0'); -- when read_bin => -- internal_output_address <= inputAddress(histogram_depth-1 downto 0); -- internal_input_address <= inputAddress(histogram_depth-1 downto 0); -- internal_write_enable <= '0'; -- bin_occupancy_bits_next <= (others => '0'); -- when write_bin => -- internal_write_enable <= '1'; -- bin_occupancy_bits_next -- <= std_logic_vector( to_unsigned(bin_occupancy + 1, histogram_width)); -- when read_out => -- -- Start reading out -- internal_output_address <= -- std_logic_vector( to_unsigned(output_address_integer, internal_output_address'length)); -- -- when continue_read_out => -- internal_output_address <= -- std_logic_vector( to_unsigned(output_address_integer, internal_output_address'length)); -- -- -- Also start to zero bins that have already been read out -- internal_write_enable <= '1'; -- bin_occupancy_bits_next <= (others => '0'); -- internal_input_address <= internal_output_address_last; -- histogram_occupancy <= bin_occupancy_bits; -- -- when stop_read_out => -- -- Stop reading, but continue to erase last bin read out -- internal_write_enable <= '1'; -- bin_occupancy_bits_next <= (others => '0'); -- internal_input_address <= internal_output_address_last; -- histogram_occupancy <= (others => '0'); -- -- when others => -- -- end case; -- -- --end if; -- -- end process; end Behavioral;