OpenCores
URL https://opencores.org/ocsvn/saturn/saturn/trunk

Subversion Repositories saturn

[/] [saturn/] [tags/] [Release IPCommunication v1.0/] [layer2_rx.vhd] - Rev 7

Compare with Previous | Blame | View Log

--============================================================================= 
--  TITRE : LAYER2_RX
--  DESCRIPTION : 
--       Analyse les trames reçues sur le port rx
--       Décapsule la partie Layer 2 et calcule le CRC
--       Note : les fanions, et l'adresse TID ne sont pas envoyées
--       dans le flux de sortie mais le CRC oui
--       Limitation : Il faut au moins 1 pulse de clk_sys au niveau '0' entre 2 
--       pulses de clk_sys à 1 du validant de donnée entrante val_in
 
--  FICHIER :        layer2_rx.vhd 
--=============================================================================
--  CREATION 
--  DATE	      AUTEUR	PROJET	REVISION 
--  10/04/2014	DRA	   SATURN	V1.0 
--=============================================================================
--  HISTORIQUE  DES  MODIFICATIONS :
--  DATE	      AUTEUR	PROJET	REVISION 
--=============================================================================
 
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
 
entity layer2_rx is
   GENERIC (
      nbbit_div : INTEGER := 10);   -- Nombre de bits pour coder le diviseur d'horloge 
   PORT (
      -- Ports système
      clk_sys  : IN  STD_LOGIC;                    -- Clock système
      rst_n    : IN  STD_LOGIC;                    -- Reset général système
      ad_mio   : IN  STD_LOGIC_VECTOR(7 DOWNTO 0); -- Adresse logique du MIO (TID)
 
      -- Interfaces ves le module SWITCH
      sw_ena   : OUT  STD_LOGIC;                   -- Indique qu'on est entre 2 trames (autorise le switch du tx)
      dat_in   : IN  STD_LOGIC_VECTOR(7 DOWNTO 0); -- Donnée parallélisée reçue sur port rx
      val_in   : IN  STD_LOGIC;                    -- validant du bus dat_in
      tc_divclk: IN  STD_LOGIC_VECTOR (nbbit_div-1 DOWNTO 0);  -- Diviseur d'horloge pour la durée d'un bit série
 
      -- Interfaces vers le module FRAME_STORE
      sof      : OUT  STD_LOGIC;                   -- Indique au module suivant le début d'une trame en réception
      eof      : OUT  STD_LOGIC;                   -- Indique au module suivant la fin d'une trame en réception
      l2_ok    : OUT  STD_LOGIC;                   -- Indique que la trame reçue est correcte d'un point de vue layer 2
      dat_out  : OUT  STD_LOGIC_VECTOR(7 downto 0);-- Données de la couche applicative (épurée de la couche layer 2)
      val_out  : OUT  STD_LOGIC                    -- Validant du bus dat_out
      );
end layer2_rx;
 
architecture  rtl of layer2_rx is
   -- Buffer prenant la valeur du flux de sortie
   SIGNAL   dat_out_buf: STD_LOGIC_VECTOR(7 downto 0);
 
   -- Timer de réception entre 2 mots reçus. Le compteur doit pouvoir mesurer 16 bits. 
   -- La durée de 1 bit est codé sur nbbit_div
   SIGNAL   cpt_timer: STD_LOGIC_VECTOR(nbbit_div+4-1 DOWNTO 0);  
   SIGNAL   timeout  : STD_LOGIC;                  -- Indique que la timer s'est écoulé
 
   SIGNAL   fanion_recu : STD_LOGIC;                  -- A 1 pour mémoriser qu'on a reçu un fanion
   SIGNAL   rec_encours : STD_LOGIC;                  -- A 1 pour indiquer qu'une trame est en cours d'analyse          
   SIGNAL   crc      : STD_LOGIC_VECTOR(15 downto 0); -- Valeur dynamique du crc
   SIGNAL   val_crc  : STD_LOGIC;                     -- Validant pour mettre à jour le CCRC
   SIGNAL   init_crc : STD_LOGIC;                     -- Initialise le calcul du CRC
 
   SIGNAL   cpt_byt  : STD_LOGIC_VECTOR(1 downto 0);  -- Pour comtper les premiers octets reçus dans la trame
   SIGNAL   adest_ok : STD_LOGIC;                     -- A 1 lorsque la trame s'adresse à ce MIO
 
   -- Machine d'état de gestion du module
   TYPE layer2_rx_type IS (idle_st, rec_st, destuf_st, endnok_st, endok_st, newdat_st);
   SIGNAL fsm_layer2_rx       : layer2_rx_type;
 
   -- Module de calcul du CRC16
	COMPONENT crc16
   GENERIC (
      poly : STD_LOGIC_VECTOR(15 downto 0) := x"1021"   -- CCITT16 par défaut
      );
	PORT(
		clk_sys  : IN std_logic;
		rst_n    : IN std_logic;
		data     : IN std_logic_vector(7 downto 0);
		val      : IN std_logic;
		init     : IN std_logic;          
		crc      : OUT std_logic_vector(15 downto 0)
		);
	END COMPONENT;
 
BEGIN
   --------------------------------------------
   -- Timer entre la réception de 2 mots consécutifs
   --------------------------------------------
   timer : PROCESS(clk_sys, rst_n)
   BEGIN
      IF (rst_n = '0') THEN
         cpt_timer <= (others => '0');
         timeout <= '0';
      ELSIF (clk_sys'EVENT and clk_sys = '1') THEN
         IF (val_in = '1') THEN
         -- Pour chaque mot reçu
            cpt_timer <= (others => '0');
            timeout <= '0';
         ELSE
         -- Entre 2 mots reçus
            cpt_timer <= cpt_timer + 1;      -- On compte les clk_sys écoulés
            IF (cpt_timer = (tc_divclk & "0000")) THEN
            -- Lorsque le comtpeur a mesuré un temps équivalent à 16 bits
               timeout <= '1';               -- On déclare un timeout (la trame en cours de réception doit être annumée)
            END IF;
         END IF;
      END IF;
   END PROCESS;
 
   --------------------------------------------
   -- Machine d'état d'analyse du flux
   --------------------------------------------
   -- Le déclenchement du timeout annule la réception d'une trame 
   man_fsm : PROCESS(clk_sys, rst_n)
   BEGIN
      IF (rst_n = '0') THEN
         fsm_layer2_rx <= idle_st;
         init_crc <= '1';
         val_crc <= '0';
         val_out <= '0';
         cpt_byt <= "00";
         eof <= '0';
         sof <= '0';           
         l2_ok <= '0';
         adest_ok <= '0';
         rec_encours <= '0';
         dat_out_buf <= (others => '0');
 
      ELSIF (clk_sys'EVENT and clk_sys = '1') THEN
         CASE fsm_layer2_rx IS
            WHEN idle_st =>
            -- Etat transitoire de remise à 0
               init_crc <= '1';
               val_crc <= '0';
               val_out <= '0';
               cpt_byt <= "00";
               eof <= '0';
               sof <= '0';           
               l2_ok <= '0';
               adest_ok <= '0';
               rec_encours <= '0';
               fanion_recu <= '0';
               fsm_layer2_rx <= rec_st;
 
            WHEN rec_st =>
            -- Etat d'attente des caractères
               val_out <= '0';            -- On s'assure que les validants ne dure qu'1 pulse
               sof <= '0';                
               val_crc <= '0';
               init_crc <= '0';
               IF (val_in = '1') THEN
               -- Sur chaque donnée reçue
                  IF (dat_in = x"7E") THEN
                  -- Si on a reçu un fanion
                     fanion_recu <= '1';        -- On mémorise le fait d'avori reçu un fanion
                     IF (rec_encours = '1') THEN
                     -- Si on reçoit un fanion et qu'on est en réception de trame, alors c'est le fanion de fin de trame
                        IF (crc(15 downto 0) = x"470F") THEN
                        -- Si le crc est égal au magic number, on valide la trame
                           fsm_layer2_rx <= endok_st;
                        ELSE
                        -- Sinon on annule la trame
                           fsm_layer2_rx <= endnok_st;
                        END IF;
                     -- Tant qu'on a reçu aucun octet, on ne considère pas les fanions
                     END IF;
                  ELSIF (fanion_recu = '1') THEN
                  -- Si on recoit une donnée autre qu'un fanion et qu'on a déjà reçu un fanion, c'est une donnée utile
                     rec_encours <= '1';              -- On est au milieu d'une trame
                     IF (dat_in = x"7D") THEN
                     -- Si c'est un mot de bourage, on va attendre le mot suivant
                        fsm_layer2_rx <= destuf_st;
                     ELSE
                     -- Si c'est une donnée normale, on la traite
                        dat_out_buf <= dat_in;     -- On mémorise la donnée à traiter pour l'état suivant
                        fsm_layer2_rx <= newdat_st;
                     END IF;
                  END IF;
               ELSIF (timeout = '1') THEN
               -- S'il s'est écoulé plus de 16 bits depuis le dernier mot reçu
                  IF (rec_encours = '1') THEN
                  -- Si on était en cours de réception de trame
                     fsm_layer2_rx <= endnok_st;      -- On va traiter une erreur
                  ELSIF (fanion_recu = '1') THEN
                  -- Si on avait juste reçu des fanions, 
                     fsm_layer2_rx <= idle_st;        -- On réinit la machine
                  END IF;
                  -- Si ona rien reçu, on reste dans cet état
               END IF;
 
            WHEN newdat_st =>
            -- Etat de traitement d'un nouveau caractère reçu (hors Fanion)
               IF (timeout = '1') THEN
               -- En cas de timeout ici on va gérer l'erreur
                  fsm_layer2_rx <= endnok_st;
               ELSE
                  fsm_layer2_rx <= rec_st;     -- Quand on aura fini de traiter on ira attendre le mot suivant
                  val_crc <= '1';              -- La valeur reçues doit être prise en comtpe dans le CRC
                  val_out <= adest_ok;         -- On n'envoie pas l'@. On n'envoie rien si le MIO n'est pas concerné
 
                  IF (cpt_byt = "01") THEN     -- On n'envoie au module suivant que le flux à partir du 2 ème octet
                     sof <= adest_ok;          -- Le premier octet indique également le début de trame au module suivant
                  END IF;
                  IF (cpt_byt /= "10") THEN
                  -- On ne compte que les 2 premiers octets
                     cpt_byt <= cpt_byt + 1;
                  END IF;
                  IF (cpt_byt = "00") THEN     -- Le premier octet indique l'adresse de destination de la trame
                     IF ((dat_out_buf = ad_mio) OR (dat_out_buf = x"90") OR (dat_out_buf = x"FF")) THEN
                     -- Le MIO peut être adressé directement (ad_mio) ou bien en multicast (90h ou FFh)
                        adest_ok <= '1';
                     ELSE
                        adest_ok <=  '0';
                     END IF;
                  END IF;
               END IF;
 
            WHEN destuf_st =>
            -- Etat de gestion du destuffing. On a reçu un caratère 7Dh
               IF (timeout = '1') THEN
                  fsm_layer2_rx <= endnok_st;
               ELSE
                  IF (val_in = '1') THEN
                  -- On attend le caractère suivant. On fonction du stuffing on fourni la bonne donnée
                     IF (dat_in = x"5E") THEN
                     -- Si l'octet de stfuffing est 5E
                        dat_out_buf <= x"7E";         -- La donnée utile est 7E
                        fsm_layer2_rx <= newdat_st;   -- On va la traiter
                     ELSIF (dat_in = x"5D") THEN
                     -- Si l'octet de stfuffing est 5E
                        dat_out_buf <= x"7D";         -- La donnée utile est 7D
                        fsm_layer2_rx <= newdat_st;   -- On va la traiter
                     ELSE
                     -- Si le stuffing est ni 5E ni 5D, c'est un cas d'erreur
                        fsm_layer2_rx <= endnok_st;
                     END IF;
                  END IF;
               END IF;
 
            WHEN endnok_st =>
            -- Cas de réception d'une mauvaise trame
               eof <= '1';          -- On indique la fin de réception au module suivant pour que l'information trame erronée soit
                                    -- reportée pour comptage
               l2_ok <= '0';        -- On indique qu'il y'a eu un problème
               rec_encours <= '0';  -- On est plus en réception de trame
               fanion_recu <= '0';
               fsm_layer2_rx <= idle_st;
 
            WHEN endok_st =>
            -- Cas de réception d'une bonne trame
               eof <= '1';          -- On indique la fin de réception (l'information bonne trame est
                                    -- aussi utilisée pour vérouiller l'autobaudrate)
               l2_ok <= '1';        -- On indique que la trame est bonne
               rec_encours <= '0';  -- On est plus en réception de trame
               fanion_recu <= '0';
               fsm_layer2_rx <= idle_st;
 
            WHEN OTHERS =>
               fsm_layer2_rx <= idle_st;
         END CASE;
      END IF;
   END PROCESS;
   dat_out <= dat_out_buf;       -- Flux de données déstuffé vers le module suivant
   sw_ena <=  NOT(rec_encours OR fanion_recu);   -- Le switch est autorisé entre 2 trames (i.e. lorsqu'une réception n'est pas en cours)
 
   --------------------------------------------
   -- Calcul du crc16
   --------------------------------------------
	inst_crc16: crc16
   GENERIC MAP (
      poly => x"1021"   -- CCITT16
      )
   PORT MAP(
		clk_sys => clk_sys,
		rst_n => rst_n,
		data => dat_out_buf,
		val => val_crc,
		init => init_crc,
		crc => crc
	);
 
end rtl;
 
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.