-- -- Transition Radiation Detector -- -- MCM Control Unit - Configuration Network -- -- -- -- $Id: mcm_nw_sendtiming.vhd,v 1.11 2002/10/13 22:06:23 rgareus Exp $ -- -- Robin Gareus, Kirchhoff Institute for Physics, Heidelberg -- rgareus@kip.uni-heidelberg.de -- ------------------------------------------------------------ -- -- Bittiming Unit -- Send/Transmitter -- -- This implements a state machine, to send out serialized data from -- the output-buffer in a given time-slice protocol. -- This unit takes control of shifting bits in the output-buffer, -- by requesting the data from there and eventually piping it -- though the bit-stuffing. After the transmission is complete, there -- is a timer wait for a given period, before sending the next frame. -- -- Components: -- This entity uses 2 timers (one for the send-speed and one to -- sleep at the end of transmission), as well as the bit-stuffing entity. -- -- Generics: -- timing_count_range: This defines the speed of trasmission. -- Set the number of internal clocks to wait -- until sending out the next bit. -- start counting at 0! must be > 2! -- so if set to 3, the network speed is 1/4 of -- the internal clock frequency. -- -- stuff_length : specifies how many identical bits are sent -- without inserting a stuff bit. -- this is forwarded to the stuffing unit -- -- timing_sleep_length:wait for how many internal clock ticks -- before a new frame may be sent. -- -- State Machine -- idle : just what it says. -- send_startbit: dito. -- send_wait : wait for next timer event to send next bit. -- send_data : send bit and if no stuff bit has been inserted -- : request next bit from output buffer -- send_sleep : delay before going back to idle state -- send_restart : during the send_sleep state, the output-buffer may -- : be filled with new data to be sent, but transmission -- : is not yet allowed (separate frames on wire see specs) -- : so queue the request, and go directly from here -- : to send_startbit skipping the idle state. -- : This state is not really neccesary but it is quite cool -- : since the NWSL does not need to wait until -- : we become idle here. This is reducing the possibilty -- : to cause an error (new frame arriving without current -- : frame beeing processed/forwarded) to almost zero. -------------------------------------------------- -- standard includes, library definitions. -------------------------------------------------- library ieee,work; use ieee.std_logic_1164.all; use work.mcm_nw_timer; use work.mcm_nw_stuffing; -------------------------------------------------- -- ENTITY -------------------------------------------------- entity mcm_nw_sendtiming is generic (timing_count_range : integer := 7; stuff_length : integer := 4; timing_sleep_length : integer := 63); port( -- Signals to phyiscal layer data_out_to_pl : out std_logic; -- data to send to physical layer --- Signal to initiate/start sending. initiate_send : in std_logic; -- start freezing out buffer -- and prepare to send. --- Communication signals to output buffer. buffer_empty : in std_logic; -- no more data in buffer data_in : in std_logic; -- next data from buffer request_data : out std_logic; -- strobe_in (shift buffer/read next) freeze_buffer : out std_logic; -- set pointer to start of buffer -- buffer will become r/o. reset_n : in std_logic; clk : in std_logic ); end mcm_nw_sendtiming; -------------------------------------------------- -- ARCHITECTURE -------------------------------------------------- architecture structural of mcm_nw_sendtiming is -------------------------------------------------- -- internal signals -------------------------------------------------- subtype state_type is std_logic_vector(2 downto 0); constant idle : state_type := "000"; constant send_startbit : state_type := "001"; constant send_wait : state_type := "010"; constant send_data : state_type := "011"; constant send_sleep : state_type := "100"; constant send_restart : state_type := "101"; SIGNAL current_state,next_state : state_type; SIGNAL d_2pl_buf : std_logic; SIGNAL timer_reset_n,timer_event_in,timer_enable : std_logic; -- sendtimer SIGNAL stuffing_start_n,stuffing_strobe_in, stuffing_data_in,stuff_bit_inserted : std_logic; -- stuffing SIGNAL sleep_enable,sleep_reset_n,sleep_event : std_logic; -- sleeptimer SIGNAL LogH : std_logic; -------------------------------------------------- -- components -------------------------------------------------- COMPONENT hamm_reg generic(Nbits : Integer := 4; Init_value : Integer := 0); port (clk, rst_n : in std_logic; data_in : in std_logic_vector(Nbits-1 downto 0); data_out : out std_logic_vector(Nbits-1 downto 0) ); END COMPONENT; COMPONENT mcm_nw_stuffing generic ( stuff_length : integer := 4); port( stuffing_data_in : in std_logic; stuffing_strobe_in : in std_logic; stuffing_start_n : in std_logic; stuff_bit_inserted : out std_logic; stuffed_data_out : out std_logic; reset_n : in std_logic; clk : in std_logic ); END COMPONENT; COMPONENT mcm_nw_timer generic (count_range,event_on : integer ); port( clk,enable,reset_n,hotreset_n,twofwd_n : IN std_logic; event,event_async : OUT std_logic ); END COMPONENT; -------------------------------------------------- -- port maps -------------------------------------------------- begin LogH <= '1'; timer_in: mcm_nw_timer generic map( count_range => timing_count_range, event_on => 0) port map ( reset_n => timer_reset_n, hotreset_n => LogH, twofwd_n => LogH, enable => timer_enable, clk => clk, event_async => timer_event_in ); sleeptimer: mcm_nw_timer generic map( count_range => timing_sleep_length, event_on => timing_sleep_length) port map ( reset_n => sleep_reset_n, hotreset_n => LogH, twofwd_n => LogH, enable => sleep_enable, clk => clk, event => sleep_event ); stuff_in: mcm_nw_stuffing generic map( stuff_length => stuff_length ) port map ( stuffing_strobe_in => stuffing_strobe_in, stuffing_data_in => stuffing_data_in, stuffing_start_n => stuffing_start_n, reset_n => reset_n, stuffed_data_out => d_2pl_buf, stuff_bit_inserted => stuff_bit_inserted, clk => clk ); --stuff_bit_inserted<='0'; --process (clk) --begin -- if (reset_n = '0') then -- d_2pl_buf<='0'; -- elsif (clk'event and clk='1') then -- if (stuffing_strobe_in = '1') then d_2pl_buf<=stuffing_data_in; end if; -- end if; --end process; -------------------------------------------------- -- processes -------------------------------------------------- -- calculate next state of the state machine: nextstate: process ( current_state, timer_event_in, stuff_bit_inserted, initiate_send, buffer_empty, sleep_event ) begin next_state <= current_state; case current_state is when idle => -- idle , wait until data arrives. if ( initiate_send = '1') then next_state <= send_startbit; -- here we go. end if; when send_startbit => -- send the startbit,start timers. next_state <= send_wait; when send_wait => -- wait until it's time to send the next bit. if ( timer_event_in = '1') then -- now it's time: if ( buffer_empty = '1') then next_state <= send_sleep; else next_state <= send_data; end if; end if; when send_data => -- request next bit from buffer (shift buffer) next_state <= send_wait; when send_sleep => -- this implements the Interframe space wait loop if ( initiate_send = '1') then -- queue new send. if ( sleep_event = '1') then next_state <= send_startbit; else next_state <= send_restart; end if; else if ( sleep_event = '1') then next_state <= idle; end if; end if; when send_restart => -- queued answer - but still have to wait. if( sleep_event = '1') then next_state <= send_startbit;end if; when OTHERS => next_state <= idle; -- THIS SHOULD NEVER HAPPEN!! end case; end process nextstate; -- state machine: enter next state. h1: hamm_reg generic map(Nbits => 3, Init_value => 0) port map ( clk => clk, rst_n => reset_n, data_in => next_state, data_out => current_state); -- set output values according to current_state. setoutput: process(current_state,reset_n,stuff_bit_inserted) begin timer_enable <= '0'; timer_reset_n <= '1'; stuffing_start_n<= '1'; freeze_buffer <= '1'; request_data <= '0'; sleep_enable <= '0'; sleep_reset_n <= '0'; case current_state is when idle => timer_reset_n <= '0'; freeze_buffer <= '0'; stuffing_start_n <= '0'; when send_startbit => timer_enable <= '1'; stuffing_start_n <= '0'; when send_wait => timer_enable <= '1'; when send_data => timer_enable <= '1'; request_data <= not stuff_bit_inserted; when send_sleep => timer_reset_n <= '0'; sleep_enable <= '1'; sleep_reset_n <= '1'; freeze_buffer <= '0'; stuffing_start_n <= '0'; when send_restart => sleep_enable <= '1'; sleep_reset_n <= '1'; when OTHERS => NULL; end case; end process setoutput; -- set Output to '0' when not in any send/transmitt state. -- pipe output through DFF. data_out_ff : process(clk) begin if (clk'event and clk='1') then if (current_state /= idle and current_state /=send_sleep and current_state /= send_restart) then data_out_to_pl <= d_2pl_buf; else data_out_to_pl <= '0'; end if; end if; end process data_out_ff; -- hardcode the start-bit. -- this can be done async, since the stuffing unit -- stores the data again in a DFF. data_to_stuffing_unit : process(current_state,timer_event_in, buffer_empty,data_in) begin if (current_state = send_startbit) then stuffing_strobe_in <= '1'; stuffing_data_in <= '1'; else stuffing_strobe_in <= timer_event_in and (not buffer_empty); stuffing_data_in <= data_in; end if; end process data_to_stuffing_unit; end structural; -------------------------------------------------- -- CONFIGURATION -------------------------------------------------- -- synopsys translate_off CONFIGURATION mcm_nw_sendtiming_CFG of mcm_nw_sendtiming is for structural for ALL : mcm_nw_timer use configuration WORK.mcm_nw_timer_CFG; end for; for ALL : mcm_nw_stuffing use configuration WORK.mcm_nw_stuffing_CFG; end for; end for; end mcm_nw_sendtiming_CFG; -- synopsys translate_on