---------------------------------------------------------------------------------- -- Company: University of Freiburg -- Engineer: Tom Barber -- -- Create Date: 16:11:35 03/11/2011 -- Design Name: -- Module Name: decoderFSM - Behavioral -- Project Name: -- Target Devices: -- Tool versions: -- Description: -- -- Dependencies: -- -- Revision: -- Revision 0.01 - File Created -- Additional Comments: -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.all; use IEEE.NUMERIC_STD.all; entity decoderFSM is generic ( depth : natural := 4; -- length of the input data (2**depth) -- Length of various bits in the data stream chipAddressLength : natural := 7; channelAddressLength : natural := 7; levelOneLength : natural := 4; bcLength : natural := 8; hitPatternLength : natural := 3 ); port( clock : in std_logic; reset : in std_logic; -- Debug status word fsm_status : out std_logic_vector(4 downto 0); -- Should we try to decode? -- This is signal from data gate decode_active : in std_logic; -- Decoded Signals found_header : out std_logic; found_hit : out std_logic; found_parseError : out std_logic; found_chipError : out std_logic; -- Last L1ID last_levelOne_out : out std_logic_vector(levelOneLength-1 downto 0); last_bcID_out : out std_logic_vector(bcLength-1 downto 0); -- Chip and channels flags hit_chip_address_out : out std_logic_vector(chipAddressLength-1 downto 0); hit_channel_address_out : out std_logic_vector(channelAddressLength-1 downto 0); hit_pattern_out : out std_logic_vector(hitPatternLength-1 downto 0); -- Interaction with the FIFO abc_fifo_data : in std_logic_vector(2**depth - 1 downto 0); fifo_read_length : out std_logic_vector(depth - 1 downto 0); fifo_occupancy : in std_logic_vector(depth downto 0); fifo_empty : in std_logic; readout_fifo : out std_logic ); end decoderFSM; architecture Behavioral of decoderFSM is -- All sorts of data constants constant header_data : std_logic_vector(4 downto 0) := "11101"; -- define the states of FSM model type state_type is ( idle, header, dataType, LOneID_BCID, SyncOne, DataHOne, DataHTwo, parseError, ChipChanAdd, SyncTwo, HitPatt, SyncThree, noHit, emptyEvent, errChipAdd, errorSep, regPatternOne, errSyncOne, regPatternTwo, errSyncTwo, regAdd, trailer ); -- States encoded into an output (mainly for debuggery) type state_encoded_array is array(state_type) of std_logic_vector(4 downto 0); constant state_encoded : state_encoded_array := ( idle => "00000", header => "10111", dataType => "00001", LOneID_BCID => "00010", SyncOne => "00100", DataHOne => "00101", DataHTwo => "00110", parseError => "11111", ChipChanAdd => "00111", SyncTwo => "01001", HitPatt => "01010", SyncThree => "01011", noHit => "01100", emptyEvent => "01101", errChipAdd => "01110", errorSep => "01111", regPatternOne => "10010", errSyncOne => "10101", regPatternTwo => "10111", errSyncTwo => "11000", regAdd => "11001", trailer => "10000" ); -- Try an array with state_type as the index type state_integer_array is array(state_type) of integer range 0 to 2**depth; -- Mapping of the state type with number of bits to read constant state_length : state_integer_array := ( idle => 0, -- Don't empty the buffer in idle header => header_data'length, LOneID_BCID => levelOneLength+bcLength, ChipChanAdd => chipAddressLength+channelAddressLength, HitPatt => hitPatternLength, -- Hit pattern errChipAdd => chipAddressLength, errorSep => 3, -- Error/config/register seperator regAdd => 5, -- Register readback address regPatternOne => 8, -- Register/config pattern 1 regPatternTwo => 8, -- Register/config pattern 2 others => 1 ); -- Map the state to an output signal next_state, current_state : state_type; signal fifo_read_length_next, fifo_read_length_internal, occupancy : integer range 0 to 2**depth; signal readout_fifo_internal : std_logic := '0'; signal fifo_can_be_read : std_logic; signal last_levelOne, last_levelOne_next : integer range 0 to 2**levelOneLength-1; signal last_bcID, last_bcID_next : integer range 0 to 2**bcLength-1; signal hit_chip_address, hit_chip_address_next : integer range 0 to 2**chipAddressLength-1; signal hit_channel_address, hit_channel_address_next : integer range 0 to 2**channelAddressLength-1; begin -- Convert internal signal to output fifo_read_length <= std_logic_vector( to_unsigned(fifo_read_length_internal, fifo_read_length'length )); occupancy <= to_integer( unsigned(fifo_occupancy) ); readout_fifo <= readout_fifo_internal; fifo_can_be_read <= not(fifo_empty); -- Debug output of the current state fsm_status <= state_encoded(current_state); -- Readout length taken from the next state fifo_read_length_next <= state_length(next_state); -- Decoded output signals hit_chip_address_out <= std_logic_vector( to_unsigned(hit_chip_address, hit_chip_address_out'length)); hit_channel_address_out <= std_logic_vector( to_unsigned(hit_channel_address, hit_channel_address_out'length)); last_levelOne_out <= std_logic_vector( to_unsigned(last_levelOne, last_levelOne_out'length)); last_bcID_out <= std_logic_vector( to_unsigned(last_bcID, last_bcID_out'length)); -- Clock process, move on state and latched signals state_reg : process(clock, reset) begin if (clock'event and clock = '1') then if (reset = '1') then current_state <= idle; fifo_read_length_internal <= 0; last_levelOne <= 0; last_bcID <= 0; hit_chip_address <= 0; hit_channel_address <= 0; else -- Only move on the state when the fifo is read out -- This allows fifo to pipe enough data through -- before we move to next state last_levelOne <= last_levelOne_next; last_bcID <= last_bcID_next; hit_chip_address <= hit_chip_address_next; hit_channel_address <= hit_channel_address_next; if ((readout_fifo_internal = '1') or (decode_active = '0')) then current_state <= next_state; fifo_read_length_internal <= fifo_read_length_next; else current_state <= current_state; fifo_read_length_internal <= fifo_read_length_internal; end if; end if; end if; end process; -- Can we read out the FIFO? readout_fifo_internal <= fifo_can_be_read and not(reset); -- State logic -- This described the state transitions only -- State dependant behaviour is described below comb_logic : process(current_state, abc_fifo_data, decode_active) begin next_state <= current_state; if (decode_active = '0') then -- Always revert to idle if the decoder is inactive -- sort of like a reset next_state <= idle; else -- use case statement to show the -- state transistion case current_state is when idle => -- This is special case, need to be told -- to expect a header by the data gate if (decode_active = '1') then next_state <= header; else next_state <= idle; end if; when header => -- Check header corresponds to expected if (abc_fifo_data(header_data'length-1 downto 0) = header_data) then next_state <= dataType; else next_state <= parseError; end if; when dataType => next_state <= LOneID_BCID; when LOneID_BCID => next_state <= SyncOne; when SyncOne => if (abc_fifo_data(0) = '1') then next_state <= DataHOne; else next_state <= parseError; end if; when DataHOne => -- If this bit is a "1", then it implies -- the start of a trailer, should -- go back to idle if (abc_fifo_data(0) = '0') then next_state <= DataHTwo; else next_state <= trailer; end if; when DataHTwo => -- DataHOne & DataHTwo = "01" --> a hit -- = "00" --> could be no hit, error or config if (abc_fifo_data(0) = '1') then next_state <= ChipChanAdd; else next_state <= noHit; end if; when parseError => -- Keep error state until deactived if (decode_active = '0') then next_state <= idle; else next_state <= parseError; end if; when ChipChanAdd => next_state <= SyncTwo; when SyncTwo => if (abc_fifo_data(0) = '1') then next_state <= HitPatt; else next_state <= parseError; end if; when HitPatt => next_state <= SyncThree; when SyncThree => -- There is a complication with sync bit 3 -- * No probs if it is a zero, then go back to DataHTwo -- * But if it is a one, could have could be: ------------------------------------------ -- 01,aaaaaaaa,ccccccc,1,hhh,1,hhh, -- ^ -- SyncThree -- Or: ------------------------------------------ -- 01,aaaaaaaa,ccccccc,1,hhh,1,0000000000000000 -- ^ -- SyncThree -- -- ie, start of another hit, or a trailer -- complicated by hit patters of '000' -- Easiest solution is to check the decode active -- but to see if data gate has found a trailer already if (decode_active = '0') then next_state <= idle; elsif (abc_fifo_data(0) = '0') then next_state <= DataHTwo; else next_state <= HitPatt; end if; when noHit => -- Could either be "0011" (no hit) -- ^ -- or "000" (error or config) -- ^ if (abc_fifo_data(0) = '1') then next_state <= emptyEvent; else next_state <= errChipAdd; end if; when emptyEvent => -- Has to be "0011" to be an empty event -- ^ if (abc_fifo_data(0) = '1') then next_state <= DataHOne; else next_state <= parseError; end if; when errChipAdd => -- Wait for the chip address next_state <= errorSep; when errorSep => -- Could now be either an error or config/register readout if (abc_fifo_data(2 downto 0) = "111") then next_state <= regPatternOne; elsif (abc_fifo_data(2 downto 0) = "010") then next_state <= regAdd; elsif ((abc_fifo_data(2 downto 0) = "001") or (abc_fifo_data(2 downto 0) = "100")) then -- In the case of error, go straight to second error bit next_state <= errSyncTwo; else next_state <= parseError; end if; when regAdd => -- Four bit register address next_state <= regPatternOne; when regPatternOne => -- Eight bit address data next_state <= errSyncOne; when errSyncOne => if (abc_fifo_data(0) = '1') then next_state <= regPatternTwo; else next_state <= parseError; end if; when regPatternTwo => next_state <= errSyncTwo; when errSyncTwo => if (abc_fifo_data(0) = '1') then next_state <= DataHOne; else next_state <= parseError; end if; when trailer => -- Trailer should always be zero if (abc_fifo_data(0) = '0') then next_state <= trailer; else next_state <= parseError; end if; when others => next_state <= idle; end case; end if; end process; -- Syncronous decoded signals hit_out : process(current_state, readout_fifo_internal, hit_chip_address, hit_channel_address, last_levelOne, last_bcID, abc_fifo_data ) begin found_hit <= '0'; hit_chip_address_next <= hit_chip_address; hit_channel_address_next <= hit_channel_address; last_levelOne_next <= last_levelOne; last_bcID_next <= last_bcID; hit_pattern_out <= (others => '0'); found_header <= '0'; found_parseError <= '0'; found_chipError <= '0'; if (readout_fifo_internal = '1') then found_hit <= '0'; found_header <= '0'; found_parseError <= '0'; hit_chip_address_next <= hit_chip_address; hit_channel_address_next <= hit_channel_address; hit_pattern_out <= (others => '0'); case current_state is when idle => -- reset all the latched signals hit_chip_address_next <= 0; hit_channel_address_next <= 0; -- Do we want the L1ID and BCID -- to reset between events? -- Uncomment the lines below if so! --last_levelOne_next <= 0; --last_bcID_next <= 0; when header => -- Make sure we have a valid header before declaring it if (abc_fifo_data(header_data'length-1 downto 0) = header_data) then found_header <= '1'; end if; when LOneID_BCID=> last_bcID_next <= to_integer( unsigned(abc_fifo_data(bcLength-1 downto 0))); last_levelOne_next <= to_integer( unsigned(abc_fifo_data(bcLength+levelOneLength-1 downto bcLength))); when ChipChanAdd=> hit_channel_address_next <= to_integer( unsigned(abc_fifo_data(channelAddressLength-1 downto 0))); hit_chip_address_next <= to_integer( unsigned(abc_fifo_data(channelAddressLength+chipAddressLength-1 downto channelAddressLength))); when errChipAdd => hit_chip_address_next <= to_integer( unsigned(abc_fifo_data(chipAddressLength-1 downto 0))); when HitPatt => -- Veto any 000 hit patterns if (abc_fifo_data(hitPatternLength-1 downto 0) /= "000") then found_hit <= '1'; else found_hit <= '0'; end if; hit_pattern_out <= abc_fifo_data(hitPatternLength-1 downto 0); when SyncThree => -- After sync bit three (after the hit pattern) -- increment the hit channel in anticipation of an -- adjancent hit. -- Don't want to go out of range of the integer if (hit_channel_address < (2**channelAddressLength-1)) then hit_channel_address_next <= hit_channel_address + 1; end if; when errSyncTwo => found_chipError <= '1'; when parseError => found_parseError <= '1'; when others => end case; end if; end process; end Behavioral; -- q(0) <= sig; -- process (clk) -- If rising_edge(clk) then -- q(1) <= q(0); -- enf if; -- end process; -- -- sig_rising <= '1' when (q = "01") else '0';