entity med_sync_control is
generic(
-- IS_SYNC_SLAVE : integer := 1;
-- IS_TX_RESET : integer := 1
++ IS_SYNC_SLAVE : integer := c_YES;
++ IS_TX_RESET : integer := c_YES;
++ USE_RETRANSMISSION : integer := c_NO
);
port(
CLK_SYS : in std_logic;
start_timer <= (others => '0');
end if;
end process;
-
+
+--PROC_RETRANS_COUNTER : process begin
+-- wait until rising_edge(CLK_SYS);
+-- if make_link_reset_real_i = '0' then
+-- request_retr_counter <= x"0000";
+-- start_retr_counter <= x"0000";
+-- end if;
+--end process;
+
+enable_chksum_comb(0) <= (MEDIA_INT2MED.ctrl_op(8) and not enable_chksum_reg(0)) when rising_edge(CLK_SYS);
+enable_chksum_comb(5 downto 1) <= not enable_chksum_reg(5 downto 1) when rising_edge(CLK_SYS);
+
+PROC_REG : process begin
+ wait until rising_edge(CLK_SYS);
+
+ if request_retr_i = '1' then
+ request_retr_counter <= std_logic_vector(unsigned(request_retr_counter) + 1);
+ end if;
+ if start_retr_i = '1' then
+ start_retr_counter <= std_logic_vector(unsigned(start_retr_counter) + 1);
+ end if;
+
+ BUS_TX.data <= x"00000000";
+ BUS_TX.unknown <= '0';
+ BUS_TX.ack <= '0';
+ if BUS_RX.write = '1' then
+ BUS_TX.ack <= '1';
+ case BUS_RX.addr(1 downto 0) is
+ when "00" => force_crc_error <= BUS_RX.data(0);
+ crc_error_delay <= BUS_RX.data(7 downto 4);
+ tx_force_crc_error <= BUS_RX.data(8);
+ tx_force_pak_error <= BUS_RX.data(9);
+ enable_chksum_reg <= BUS_RX.data(21 downto 16);
+ when "01" => force_crc_error <= '0'; tx_force_crc_error <= '0'; tx_force_pak_error <= '0';
+ request_retr_counter <= x"0000"; start_retr_counter <= x"0000";
+ when others => BUS_TX.unknown <= '1';
+ end case;
+ elsif BUS_RX.read = '1' then
+ BUS_TX.ack <= '1';
+ case BUS_RX.addr(1 downto 0) is
- when "00" => BUS_TX.data <= x"00" & got_fatal_error & got_chksum & enable_chksum_reg & x"0" & "00" & tx_force_pak_error & tx_force_crc_error & crc_error_delay & "000" & force_crc_error;
++ when "00" =>
++ if USE_RETRANSMISSION = c_YES then
++ BUS_TX.data <= x"00" & got_fatal_error & got_chksum & enable_chksum_reg & x"0" & "00" & tx_force_pak_error & tx_force_crc_error & crc_error_delay & "000" & force_crc_error;
++ else
++ BUS_TX.data <= x"10000000";
++ end if;
+ when "01" => BUS_TX.data <= request_retr_counter & start_retr_counter;
+ --when "11" => BUS_TX.data <= x"000000" & DEBUG_RX_CONTROL_i(31 downto 24);
+ when others => BUS_TX.unknown <= '1';
+ end case;
+ end if;
+
+ if last_FORCE_CRC_ERROR_IN = '0' and FORCE_CRC_ERROR_IN = '1' then
+ force_crc_error <= '1';
+ elsif request_retr_i = '1' then
+ force_crc_error <= '0';
+ end if;
+
+ if tx_got_force_error_100 = '1' then
+ tx_force_crc_error <= '0';
+ tx_force_pak_error <= '0';
+ end if;
+
+end process;
+
-------------------------------------------------
-- TX Data
-------------------------------------------------
THE_TX : tx_control
++ generic map(
++ USE_RETRANSMISSION => USE_RETRANSMISSION
++ )
port map(
CLK_200 => CLK_TXI,
CLK_100 => CLK_SYS,
-- RX Data
-------------------------------------------------
THE_RX_CONTROL : rx_control
++ generic map(
++ USE_RETRANSMISSION => USE_RETRANSMISSION
++ )
port map(
CLK_200 => CLK_RXI,
CLK_100 => CLK_SYS,
use work.med_sync_define.all;
entity rx_control is
++ generic(
++ USE_RETRANSMISSION : integer := c_YES
++ );
port(
CLK_200 : in std_logic;
CLK_100 : in std_logic;
-- Data to Endpoint
----------------------------------------------------------------------
- process begin
- wait until rising_edge(CLK_100);
-
- --switch only when fifo is empty:
- if is_idle_100 = '1' and ct_fifo_empty = '1' and load_use_crc_100 = '1' and fatal_error = '0' then
- --if ct_fifo_empty = '1' and load_use_crc_100 = '1' then
- use_crc <= '1';
- elsif (ct_fifo_empty = '1' and load_use_crc_100 = '0') then
- use_crc <= '0';
- end if;
+
+ct_fifo_read <= not ct_fifo_reset and not ct_fifo_empty and (got_pulse_good or got_pulse_bad or not use_crc);
+GOT_CHKSUM <= use_crc;
+GOT_FATAL_ERROR <= fatal_error;
+
+-- 100 MHz registers
+buf_RX_DATA_OUT <= ct_fifo_data_out(15 downto 0) when rising_edge(CLK_100);
+RX_DATA_OUT <= buf_RX_DATA_OUT;
+RX_WRITE_OUT <= buf2_rx_write_out;
+RX_PACKET_NUMBER_OUT <= rx_packet_num when rising_edge(CLK_100);
+
+last_ct_fifo_read <= ct_fifo_read when rising_edge(CLK_100);
+last_ct_fifo_empty <= ct_fifo_empty when rising_edge(CLK_100);
+last_use_crc <= use_crc when rising_edge(CLK_100);
+reset_retrans <= RESET_RETRANSMIT_IN when rising_edge(CLK_100);
+
+-- 200 to 100 MHz transfer
+load_use_crc_100_i <= load_use_crc when rising_edge(CLK_100);
+load_use_crc_100 <= load_use_crc_100_i when rising_edge(CLK_100);
+is_idle_100_i <= is_idle when rising_edge(CLK_100);
+is_idle_100 <= is_idle_100_i when rising_edge(CLK_100);
+
+-- 100 to 200 MHz transfer
+force_crc_error_200_i <= force_crc_error when rising_edge(CLK_200);
+force_crc_error_200 <= force_crc_error_200_i when rising_edge(CLK_200);
+CRC_ERROR_DELAY_200_i <= CRC_ERROR_DELAY when rising_edge(CLK_200);
+CRC_ERROR_DELAY_200 <= CRC_ERROR_DELAY_200_i when rising_edge(CLK_200);
+use_crc_200_i <= use_crc when rising_edge(CLK_200);
+use_crc_200 <= use_crc_200_i when rising_edge(CLK_200);
+enable_chksum_200_i <= ENABLE_CHKSUM when rising_edge(CLK_200);
+enable_chksum_200 <= enable_chksum_200_i when rising_edge(CLK_200);
+reset_retrans_200_i <= reset_retrans when rising_edge(CLK_200);
+reset_retrans_200 <= reset_retrans_200_i when rising_edge(CLK_200);
+RESET_IN_200_i <= RESET_IN when rising_edge(CLK_200);
+RESET_IN_200 <= RESET_IN_200_i when rising_edge(CLK_200);
+RX_RESET_FINISHED_200_i <= RX_RESET_FINISHED when rising_edge(CLK_200);
+RX_RESET_FINISHED_200 <= RX_RESET_FINISHED_200_i when rising_edge(CLK_200);
+
+
++gen_used_retransmission : if USE_RETRANSMISSION = c_YES generate
++ process
++ begin
++ wait until rising_edge(CLK_100);
+
- if use_crc = '1' then
- --fatal error, disable mechanism
- if is_idle_100 = '1' and ct_fifo_empty = '0' then
- fatal_counter <= fatal_counter + 1;
- if fatal_counter = 15 then -- 6 idles with full fifo means something is wrong
- fatal_error <= '1';
- use_crc <= '0';
++ --switch only when fifo is empty:
++ if is_idle_100 = '1' and ct_fifo_empty = '1' and load_use_crc_100 = '1' and fatal_error = '0' then
++ --if ct_fifo_empty = '1' and load_use_crc_100 = '1' then
++ use_crc <= '1';
++ elsif (ct_fifo_empty = '1' and load_use_crc_100 = '0') then
++ use_crc <= '0';
++ end if;
+
- else
- fatal_counter <= "0000";
++ if use_crc = '1' then
++ --fatal error, disable mechanism
++ if is_idle_100 = '1' and ct_fifo_empty = '0' then
++ fatal_counter <= fatal_counter + 1;
++ if fatal_counter = 15 then -- 6 idles with full fifo means something is wrong
++ fatal_error <= '1';
++ use_crc <= '0';
++ end if;
++ else
++ fatal_counter <= "0000";
+ end if;
- end if;
-
- --some logic to remember the state:
- if (pulse_good_100 = '1' or latched_pulse_good_100 /= "00") and (ct_fifo_empty = '1' or num_read_words = 0) then
- got_pulse_good <= '1';
- got_pulse_bad <= '0';
- if latched_pulse_good_100 /= "00" then
- latched_pulse_good_100 <= latched_pulse_good_100 - 1;
- end if;
- elsif pulse_good_100 = '1' then
- latched_pulse_good_100 <= latched_pulse_good_100 + 1;
- elsif (pulse_bad_100 = '1' or latched_pulse_bad_100 /= "00") and (ct_fifo_empty = '1' or num_read_words = 0) then
- got_pulse_bad <= '1';
- got_pulse_good <= '0';
- if latched_pulse_bad_100 /= "00" then
- latched_pulse_bad_100 <= latched_pulse_bad_100 - 1;
- end if;
- elsif pulse_bad_100 = '1' then
- latched_pulse_bad_100 <= latched_pulse_bad_100 + 1;
- end if;
-
- --switching the good/bad mode is only allowed after complete pakets
- --(otherwise the current transfer is interrupted)
- if ct_fifo_empty = '1' or num_read_words = 4 or use_crc = '0' then
- if latched_pulse_bad_100 = "00" then
+ end if;
- end if;
- if latched_pulse_good_100 = "00" then
++
++ --some logic to remember the state:
++ if (pulse_good_100 = '1' or latched_pulse_good_100 /= "00") and (ct_fifo_empty = '1' or num_read_words = 0) then
++ got_pulse_good <= '1';
+ got_pulse_bad <= '0';
-ct_fifo_read <= not ct_fifo_reset and not ct_fifo_empty; -- when rising_edge(CLK_100);
-buf_rx_write_out <= last_ct_fifo_read and not last_ct_fifo_empty when rising_edge(CLK_100);
-
-RX_DATA_OUT <= ct_fifo_data_out(15 downto 0) ;
-RX_WRITE_OUT <= buf_rx_write_out;
-RX_PACKET_NUMBER_OUT <= rx_packet_num;
-
-last_ct_fifo_read <= ct_fifo_read when rising_edge(CLK_100);
-last_ct_fifo_empty <= ct_fifo_empty when rising_edge(CLK_100);
-
-process begin
- wait until rising_edge(CLK_100);
- if RX_ALLOW_IN = '0' then
- rx_packet_num <= "100";
- elsif buf_rx_write_out = '1' then
- if rx_packet_num = "100" then
- rx_packet_num <= "000";
++ if latched_pulse_good_100 /= "00" then
++ latched_pulse_good_100 <= latched_pulse_good_100 - 1;
++ end if;
++ elsif pulse_good_100 = '1' then
++ latched_pulse_good_100 <= latched_pulse_good_100 + 1;
++ elsif (pulse_bad_100 = '1' or latched_pulse_bad_100 /= "00") and (ct_fifo_empty = '1' or num_read_words = 0) then
++ got_pulse_bad <= '1';
+ got_pulse_good <= '0';
++ if latched_pulse_bad_100 /= "00" then
++ latched_pulse_bad_100 <= latched_pulse_bad_100 - 1;
++ end if;
++ elsif pulse_bad_100 = '1' then
++ latched_pulse_bad_100 <= latched_pulse_bad_100 + 1;
++ end if;
+
- num_read_words <= "000";
- elsif use_crc = '1' and ct_fifo_read = '1' then
- num_read_words <= num_read_words + 1;
- end if;
-
- --the following lines catches the case that an incomplete paket is merged
- --with the fresh new paket after resubmit
- --(see also pulse_bad in GET_RETR)
- if (pulse_good_100 = '1' or latched_pulse_good_100 /= "00") and got_pulse_bad = '1' and num_read_words /= "010" and ct_fifo_data_out(16) = '1' then
- buf_rx_write_out <= '1';
- got_pulse_good <= '1';
- got_pulse_bad <= '0';
- num_read_words <= "011";
- latched_pulse_good_100 <= "00";
- last_got_pulse_bad <= '0';
- else
- --thats like it should work in normal mode:
- buf_rx_write_out <= last_ct_fifo_read and not last_ct_fifo_empty and not got_pulse_bad;
- if last_got_pulse_bad = '1' then
- buf_rx_write_out <= '0';
++ --switching the good/bad mode is only allowed after complete pakets
++ --(otherwise the current transfer is interrupted)
++ if ct_fifo_empty = '1' or num_read_words = 4 or use_crc = '0' then
++ if latched_pulse_bad_100 = "00" then
++ got_pulse_bad <= '0';
++ end if;
++ if latched_pulse_good_100 = "00" then
++ got_pulse_good <= '0';
++ end if;
++ num_read_words <= "000";
++ elsif use_crc = '1' and ct_fifo_read = '1' then
++ num_read_words <= num_read_words + 1;
+ end if;
- rx_packet_num <= std_logic_vector(unsigned(rx_packet_num)+1);
- end if;
- end if;
-end process;
++
++ --the following lines catches the case that an incomplete paket is merged
++ --with the fresh new paket after resubmit
++ --(see also pulse_bad in GET_RETR)
++ if (pulse_good_100 = '1' or latched_pulse_good_100 /= "00") and got_pulse_bad = '1' and num_read_words /= "010" and ct_fifo_data_out(16) = '1' then
++ buf_rx_write_out <= '1';
++ got_pulse_good <= '1';
++ got_pulse_bad <= '0';
++ num_read_words <= "011";
++ latched_pulse_good_100 <= "00";
++ last_got_pulse_bad <= '0';
+ else
- last_got_pulse_bad <= got_pulse_bad;
- end if;
-
- if send_link_reset_i = '1' or reset_retrans = '1' then
- good_pos_counter <= (others => '0');
- got_pulse_good <= '0';
- got_pulse_bad <= '0';
- num_read_words <= "000";
- latched_pulse_good_100 <= "00";
- latched_pulse_bad_100 <= "00";
- use_crc <= '0';
- fatal_error <= '0';
- elsif last_use_crc = '0' and buf_rx_write_out = '1' then
- good_pos_counter <= std_logic_vector(unsigned(good_pos_counter)+1);
- elsif pulse_good_100 = '1' then
- good_pos_counter <= std_logic_vector(unsigned(good_pos_counter)+5);
- end if;
++ --thats like it should work in normal mode:
++ buf_rx_write_out <= last_ct_fifo_read and not last_ct_fifo_empty and not got_pulse_bad;
++ if last_got_pulse_bad = '1' then
++ buf_rx_write_out <= '0';
++ end if;
++ last_got_pulse_bad <= got_pulse_bad;
++ end if;
++
++ if send_link_reset_i = '1' or reset_retrans = '1' then
++ good_pos_counter <= (others => '0');
++ got_pulse_good <= '0';
++ got_pulse_bad <= '0';
++ num_read_words <= "000";
++ latched_pulse_good_100 <= "00";
++ latched_pulse_bad_100 <= "00";
++ use_crc <= '0';
++ fatal_error <= '0';
++ elsif last_use_crc = '0' and buf_rx_write_out = '1' then
++ good_pos_counter <= std_logic_vector(unsigned(good_pos_counter)+1);
++ elsif pulse_good_100 = '1' then
++ good_pos_counter <= std_logic_vector(unsigned(good_pos_counter)+5);
+ end if;
- if RX_ALLOW_IN = '0' then
- rx_packet_num <= "100";
- elsif buf_rx_write_out = '1' then
- if rx_packet_num = "100" then
- rx_packet_num <= "000";
+
- rx_packet_num <= std_logic_vector(unsigned(rx_packet_num)+1);
- end if;
- end if;
- end process;
-
- process begin
- wait until rising_edge(CLK_100);
- if (pulse_good_100 = '1' or latched_pulse_good_100 /= "00") and got_pulse_bad = '1' and num_read_words /= "010" and ct_fifo_data_out(16) = '1' then
- buf2_rx_write_out <= '1';
- else
++ if RX_ALLOW_IN = '0' then
++ rx_packet_num <= "100";
++ elsif buf_rx_write_out = '1' then
++ if rx_packet_num = "100" then
++ rx_packet_num <= "000";
++ else
++ rx_packet_num <= std_logic_vector(unsigned(rx_packet_num)+1);
++ end if;
++ end if;
++ end process;
++
++ process
++ begin
++ wait until rising_edge(CLK_100);
++ if (pulse_good_100 = '1' or latched_pulse_good_100 /= "00") and got_pulse_bad = '1' and num_read_words /= "010" and ct_fifo_data_out(16) = '1' then
++ buf2_rx_write_out <= '1';
+ else
- end if;
- end process;
-
++ buf2_rx_write_out <= buf_rx_write_out;
++ end if;
++ end process;
++end generate;
++
++gen_no_retransmission : if USE_RETRANSMISSION = c_NO generate
++ process
++ begin
++ wait until rising_edge(CLK_100);
++
+ buf2_rx_write_out <= buf_rx_write_out;
++ use_crc <= '0';
++
++ if send_link_reset_i = '1' or reset_retrans = '1' then
++ good_pos_counter <= (others => '0');
++ num_read_words <= "000";
++ use_crc <= '0';
++ fatal_error <= '0';
++ end if;
++
++ if RX_ALLOW_IN = '0' then
++ rx_packet_num <= "100";
++ elsif buf_rx_write_out = '1' then
++ if rx_packet_num = "100" then
++ rx_packet_num <= "000";
++ else
++ rx_packet_num <= std_logic_vector(unsigned(rx_packet_num)+1);
++ end if;
++ end if;
++
++ buf_rx_write_out <= last_ct_fifo_read and not last_ct_fifo_empty;
++ end process;
++end generate;
----------------------------------------------------------------------
-- Clock Domain Transfer
ct_fifo_reset <= not RX_ALLOW_IN when rising_edge(CLK_200);
+----------------------------------------------------------------------
+-- CRC
+----------------------------------------------------------------------
+
+crc_data <= reg_rx_data_in when rising_edge(CLK_200);
+
++gen_used_retransmission2 : if USE_RETRANSMISSION = c_YES generate
+CRC_CALC : trb_net_CRC8
+ port map(
+ CLK => CLK_200,
+ RESET => crc_reset,
+ CLK_EN => crc_en,
+ DATA_IN => crc_data,
+ CRC_OUT => crc_q,
+ CRC_match => open
+ );
++end generate;
+
----------------------------------------------------------------------
-- Read incoming data
----------------------------------------------------------------------
ct_fifo_write <= '1';
rx_state <= FIRST;
else
- rx_state <= FIRST; -- SLEEP;
+ rx_state <= FIRST; -- SLEEP;
end if;
-
+
+ when GET_CRC1 =>
+ -- first time
- load_use_crc <= '1';
++ if USE_RETRANSMISSION = c_YES then
++ load_use_crc <= '1';
++ end if;
+ if disable_crc = '0' then
+ disable_crc <= '1';
+ end if;
+ force_crc_error_int <= '0';
+ crc_reset <= '1';
+ rx_state <= FIRST;
+ num_pakets <= (others => '0');
+
+ when GET_CRC2 =>
+ if ((crc_q /= reg_rx_data_in and enable_chksum_200(1) = '1')
+ or (force_crc_error_200 = '1' and CRC_ERROR_DELAY_cnt = "0000")
+ or waiting_for_retr = '1'
+ or (num_pakets /= 5 and enable_chksum_200(2) = '1')
+ or force_crc_error_int = '1') and enable_chksum_200(0) = '1' then
+ -- bad
+ if disable_crc = '0' then
+ pulse_bad <= '1';
+ if waiting_for_retr = '0' then
+ req_retr_i <= '1';
+ reset_timeout <= '1';
+ waiting_for_retr <= '1';
+ end if;
+ else
+ -- this disables errors until at least one good has been passed
+ pulse_good <= '1';
+ end if;
+ else
+ -- good
+ pulse_good <= '1';
+ if force_crc_error_200 = '0' then
+ CRC_ERROR_DELAY_cnt <= CRC_ERROR_DELAY_200;
+ disable_crc <= '0';
+ else
+ CRC_ERROR_DELAY_cnt <= std_logic_vector(unsigned(CRC_ERROR_DELAY_cnt) - 1);
+ end if;
+ end if;
+ force_crc_error_int <= '0';
+ crc_reset <= '1';
+ rx_state <= FIRST;
+ num_pakets <= (others => '0');
+
+ when GET_RETR =>
+ if force_crc_error_200 = '1' then
+ disable_crc <= '1';
+ end if;
+ if num_pakets /= "0000" then --incomplete packet
+ pulse_bad <= '1';
+ end if;
+ rx_state <= FIRST;
+ waiting_for_retr <= '0';
+ crc_reset <= '1';
+ num_pakets <= (others => '0');
+ resub_mode <= '1';
+ next_sop <= '1';
+ reset_timeout <= '1';
+
when GET_DLM =>
rx_state_bits <= x"5";
rx_dlm_i <= '1';