URL
https://opencores.org/ocsvn/saturn/saturn/trunk
Subversion Repositories saturn
[/] [saturn/] [trunk/] [FPGA Concentrateur SIL4/] [fpga_cosil4/] [con_layer2_tx.vhd] - Rev 11
Go to most recent revision | Compare with Previous | Blame | View Log
--============================================================================= -- TITRE : CON_LAYER2_TX -- DESCRIPTION : -- Encapsule la trame applicative dans une trame Layer2 -- Ajoute les fanions de début et de fin, effectue le byte stuffing -- et calcule le CRC -- FICHIER : layer2_tx.vhd --============================================================================= -- CREATION -- DATE AUTEUR PROJET REVISION -- 10/04/2014 DRA SATURN V1.0 --============================================================================= -- HISTORIQUE DES MODIFICATIONS : -- DATE AUTEUR PROJET REVISION -- 27/04/15 DRA SATURN V1.1 -- Suppression du test de FIFO vide dans l'état waitendsend_st. Ce temps -- permettait de laisser un blanc sur la ligne pour laisser le temps -- à un noeud d'insérer sa réponse, mais la stratégie de priorité à l'anneau -- fait que ce n'est plus utile --============================================================================= LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_ARITH.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL; entity con_layer2_tx is PORT ( -- Ports système clk_sys : IN STD_LOGIC; -- Clock système rst_n : IN STD_LOGIC; -- Reset général système stuf_phys: IN STD_LOGIC; -- Ordre d'émission de caractères 7F sur la ligne acq_stuf : OUT STD_LOGIC; -- Indique que le stuff est fini -- Interfaces vers le module d'interface du PIC dat_in : IN STD_LOGIC_VECTOR(7 DOWNTO 0); -- Flux de données applicatives à émettre -- La première donnée du flux qui suit le sof est l'@ de destination val_in : IN STD_LOGIC; -- validant du bus dat_in sof : IN STD_LOGIC; -- Indique le début d'une trame à émettre (non synchrone de la 1ère donnée) eof : IN STD_LOGIC; -- Indique le dernier octet de la trame à émettre datin_free: OUT STD_LOGIC; -- Indique que le module layer2_tx est prêt à recevoir 1 octet suivant -- Interfaces vers les FIFO de transmissions dat_out : OUT STD_LOGIC_VECTOR(7 downto 0);-- Flux de données Layer2 à stocker dans les FIFO Tx val_out : OUT STD_LOGIC; -- Validant du bus dat_out clr_fifo : IN STD_LOGIC; -- Signal de reset des FIFO Tx progfull1: IN STD_LOGIC; -- Indique la FIFO Tx1 est presque pleine progfull2: IN STD_LOGIC; -- Indique la FIFO Tx2 est presque pleine full1 : IN STD_LOGIC; -- Indique la FIFO Tx1 est pleine empty1 : IN STD_LOGIC; -- Indique la FIFO Tx1 est vide full2 : IN STD_LOGIC; -- Indique la FIFO Tx2 est pleine empty2 : IN STD_LOGIC -- Indique la FIFO Tx2 est vide ); end con_layer2_tx; architecture rtl of con_layer2_tx is SIGNAL crc : STD_LOGIC_VECTOR(15 downto 0); -- Valeur dynamique du crc SIGNAL val_crc : STD_LOGIC; -- Validant du CCRC SIGNAL init_crc : STD_LOGIC; -- Initialise le calcul du CRC SIGNAL dat_crc : STD_LOGIC_VECTOR(7 DOWNTO 0); -- Donnée à prendre en compte pour le calcul du CRC SIGNAL last_char: STD_LOGIC; -- Pour mémoriser le eof au cas ou il y'ait du stuffing sur le dernier char SIGNAL cpt_stuf : STD_LOGIC_VECTOR(9 DOWNTO 0); -- Pour compter les octets de stuff de ligne envoyés SIGNAL acq_stuf_buf : STD_LOGIC; -- Pour indiquer la focntion de stuff en cours SIGNAL empty1_r1, empty1_r2: STD_LOGIC; -- Pour changer empty1 d'horloge SIGNAL empty2_r1, empty2_r2: STD_LOGIC; -- Pour changer empty2 d'horloge -- Machine d'état de gestion du module TYPE layer2_tx_type IS (idle_st, addest_st, data_st, fifo_full_st, stuf5E_st, stuf5D_st, waitcrc_st, crc1_st, stufcrc1_st, crc2_st, stufcrc2_st, fanionfin_st, waitendsend_st, stuf_st, wait_stuf_st); SIGNAL fsm_layer2_tx : layer2_tx_type; -- Module de calcul du CRC16 COMPONENT crc16 GENERIC ( poly : STD_LOGIC_VECTOR(15 downto 0) := x"1021" ); 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 acq_stuf <= acq_stuf_buf; -------------------------------------------- -- Machine d'état de génération du flux et d'écriture dans la FIFO Tx -- Les FIFO Tx font 512 octet mais leur 'prog_full' est calé à 495 octets -- En testant le prog_full, on a donc toujours au moins 15 octets de libre -- On ne teste donc le prog_full que quand on écrit des donées utiles de la trame -- Lorsqu'on écrit l'entête ou le CRC ou du stuffing, il n 'y a pas besoin de tester -- le niveau de remplissage -------------------------------------------- -- La donnée entrante est prise en compte que si on est dans l'état data_st ou addest_st -- Autrement dit, le module est dipos pour une nouvelle donnée dans ces cas là datin_free <= '1' WHEN (fsm_layer2_tx = data_st OR fsm_layer2_tx = addest_st) ELSE '0'; man_fsm : PROCESS(clk_sys, rst_n) BEGIN IF (rst_n = '0') THEN fsm_layer2_tx <= idle_st; init_crc <= '1'; val_crc <= '0'; val_out <= '0'; last_char <= '0'; acq_stuf_buf <= '0'; empty1_r1 <= '0'; empty1_r2 <= '0'; empty2_r1 <= '0'; empty2_r2 <= '0'; dat_out <= (others => '0'); dat_crc <= (others => '0'); ELSIF (clk_sys'EVENT and clk_sys = '1') THEN empty1_r1 <= empty1; -- Changement d'horloge de empty1 empty1_r2 <= empty1_r1; empty2_r1 <= empty2; -- Changement d'horloge de empty2 empty2_r2 <= empty2_r1; CASE fsm_layer2_tx IS WHEN idle_st => -- Etat d'attente du signal sof ou d'un ordre de de stuf de la ligne physique IF (stuf_phys = '1' AND acq_stuf_buf = '0') THEN -- Si on reçoit un ordre de stuf de la ligne physique et que ce n'est pas l'ordre précédent pas encore effacé dat_out <= x"7E"; -- On n'envoie que des fanions init_crc <= '0'; -- On annule le reset du CRC val_crc <= '0'; -- L'octet qu'on va sortir ne compte pas dans le calcul du crc val_out <= '1'; -- On l'écrit dans la FIFO cpt_stuf <= (OTHERS => '0'); fsm_layer2_tx <= stuf_st; -- On va générer cpt_stuf fanions sur la ligne ELSIF (sof = '1' AND full1 = '0' AND full2 = '0' AND clr_fifo = '0') THEN -- Si on commence une trame et que le processus de clr est terminé -- Lors d'un reset de fifo, le flag full reste actif durant quelques cycle après -- le relachement du clr_fifo dat_out <= x"7E"; -- On envoie le fanion de début init_crc <= '0'; -- On annule le reset du CRC val_crc <= '0'; -- L'octet qu'on va sortir ne compte pas dans le calcul du crc val_out <= '1'; -- On l'écrit dans la FIFO fsm_layer2_tx <= addest_st; -- On va générer l'octet de commande ELSE -- Si pas de début de trame init_crc <= '1'; -- On initialise le CRC val_crc <= '0'; -- On fait rien val_out <= '0'; END IF; acq_stuf_buf <= '0'; WHEN addest_st => IF (val_in = '1') THEN -- La première donnée de la trmae est l'@ destination. Elle ne peut pas être stuffée car 7E et 7D sont interdites val_out <= '1'; -- Quelle que soit la donnée on la prend en compte dans le calcul du CRC val_crc <= '1'; -- Elle compte dans le calcul du CRC dat_out <= dat_in; -- On la fournit à la FIFO dat_crc <= dat_in; -- On la forunit au CRC fsm_layer2_tx <= data_st; -- On va traiter l'octet suivant ELSE -- Tant qu'on recoit pas de donnée val_out <= '0'; -- Rien dans le FIFO val_crc <= '0'; -- CRC inchangé END IF; WHEN data_st => -- On attend une donnée disponible sur le bus d'entrée IF (val_in = '1') THEN -- Si il y'a une donnée sur le bus val_crc <= '1'; -- Quelle que soit la donnée on la prend en compte dans le calcul du CRC dat_crc <= dat_in; val_out <= '1'; -- Quelle que soit la donnée on va écrire quelque chose dans la FIFO IF (dat_in = x"7E") THEN dat_out <= x"7D"; -- Si c'est un 7E il doit être remplacé par la séquence 7D 5E last_char <= eof; -- On mémorise s'il s'agit du dernier char de la trame fsm_layer2_tx <= stuf5E_st;-- On va insérer le code 5E dans le flux ELSIF (dat_in = x"7D") THEN dat_out <= x"7D"; -- Si c'est un 7D il doit être remplacé par la séquence 7D 5D last_char <= eof; -- On mémorise s'il s'agit du dernier char de la trame fsm_layer2_tx <= stuf5D_st;-- On va insérer le code 5D dans le flux ELSE -- Si c'est une donnée normale dat_out <= dat_in; -- On la met dans le flux IF (eof = '1') THEN -- Si c'est la dernière donnée de la trame fsm_layer2_tx <= waitcrc_st; -- On va attendre que le CRC soit prêt ELSIF (progfull1 = '1' OR progfull2 = '1') THEN -- Si une des 2 FIFO en écriture est presque pleine fsm_layer2_tx <= fifo_full_st; -- On va attendre END IF; END IF; ELSE -- Si il n'y a pas de nouvelle donnée sur le bus val_crc <= '0'; -- On fait rien val_out <= '0'; END IF; WHEN fifo_full_st => -- Etat d'attente qu'il y'ait de la place dans les FIFO en écriture val_crc <= '0'; -- On fait rien val_out <= '0'; IF (progfull1 = '0' AND progfull2 = '0') THEN -- On attend que les 2 FIFO ne soient plus pleines fsm_layer2_tx <= data_st; END IF; WHEN stuf5E_st => -- Etat d'insertion du char 5E dans le flux dat_out <= x"5E"; val_crc <= '0'; -- Le CRC ne doit pa sêtre mis à jour avec l'octet de bourrage val_out <= '1'; -- On l'écrit dans la FIFO IF (last_char = '1') THEN -- Si c'était le dernier octet, on va insérer le CRC fsm_layer2_tx <= crc1_st; ELSE fsm_layer2_tx <= data_st; END IF; WHEN stuf5D_st => -- Etat d'insertion du char 5D dans le flux dat_out <= x"5D"; val_crc <= '0'; -- Le CRC ne doit pa sêtre mis à jour avec l'octet de bourrage val_out <= '1'; -- On l'écrit dans la FIFO IF (last_char = '1') THEN -- Si c'était le dernier octet, on va insérer le CRC fsm_layer2_tx <= crc1_st; ELSE fsm_layer2_tx <= data_st; END IF; WHEN waitcrc_st => -- On attend un cycle que le CRC soit à jour avec la dernière donnée val_crc <= '0'; val_out <= '0'; fsm_layer2_tx <= crc1_st; -- On va traiter les 8 MSB du CRC WHEN crc1_st => -- Etat de traitement des 8 MSB du CRC val_crc <= '0'; -- On doit pas modifier le CRC val_out <= '1'; -- On va écrire une donnée en FIFO IF (crc(15 downto 8) = x"7E" OR crc(15 downto 8) = x"7D") THEN -- Si les 8 MSB sont une donnée à stuffer dat_out <= x"7D"; -- On écrit le code de stuffing fsm_layer2_tx <= stufcrc1_st; -- On va traiter le stuf ELSE -- Si les 8 MSB ne sont pas à stuffer dat_out <= crc(15 downto 8); -- On les met tel quel dans le flux fsm_layer2_tx <= crc2_st; -- On va traiter les 8 LSB du CRC END IF; WHEN stufcrc1_st => -- Etat de gestion du stuffing des 8 MSB du CRC val_crc <= '0'; val_out <= '1'; IF (crc(15 downto 8) = x"7E") THEN -- Selon la valeur à stuffer dat_out <= x"5E"; -- On envoie le bon code ELSE dat_out <= x"5D"; END IF; fsm_layer2_tx <= crc2_st; -- On va traiter les 8 LSB du CRC WHEN crc2_st => -- Etat de traitement des 8 LSB du CRC val_crc <= '0'; val_out <= '1'; IF (crc(7 downto 0) = x"7E" OR crc(7 downto 0) = x"7D") THEN -- Si les 8 LSB sont une donnée à stuffer dat_out <= x"7D"; fsm_layer2_tx <= stufcrc2_st; ELSE -- Si les 8 MSB ne sont pas à stuffer dat_out <= crc(7 downto 0); fsm_layer2_tx <= fanionfin_st; -- On va insérer le fanion de fin dans le flux END IF; WHEN stufcrc2_st => -- Etat de gestion du stuffing des 8 LSB du CRC val_crc <= '0'; val_out <= '1'; IF (crc(7 downto 0) = x"7E") THEN dat_out <= x"5E"; ELSE dat_out <= x"5D"; END IF; fsm_layer2_tx <= fanionfin_st; WHEN fanionfin_st => -- On envoie le fanion de fin dat_out <= x"7E"; val_crc <= '0'; init_crc <= '1'; val_out <= '1'; fsm_layer2_tx <= waitendsend_st; -- On va attendre la fin des transmission WHEN waitendsend_st => -- Etat d'annulation de l'émission val_out <= '0'; fsm_layer2_tx <= idle_st; WHEN stuf_st => -- Envoie cpt_stuf fanion sur la ligne IF (cpt_stuf = CONV_STD_LOGIC_VECTOR(800, cpt_stuf'LENGTH)) THEN -- Si on a émis tous les fanions fsm_layer2_tx <= wait_stuf_st; val_out <= '0'; -- On n'écrit plus rien dans la FIFO ELSE -- Tant qu'il faut émettre IF (progfull1 = '1' OR progfull2 = '1') THEN -- Si une des 2 FIFO Tx est pleine val_out <= '0'; -- On attend sans ecrire ELSE val_out <= '1'; -- Chaque octet écrit est décompté cpt_stuf <= cpt_stuf + 1; END IF; END IF; WHEN wait_stuf_st => -- Etat d'attente que les mots de stuff soit tous partis IF (empty1_r2 = '1' AND empty2_r2 = '1') THEN -- Si les 2 FIFO Tx sont vides acq_stuf_buf <= '1'; -- On signale que l'opération est finie fsm_layer2_tx <= idle_st; END IF; WHEN OTHERS => fsm_layer2_tx <= idle_st; END CASE; END IF; END PROCESS; -------------------------------------------- -- Calcul du crc16 -------------------------------------------- inst_crc16: crc16 GENERIC MAP ( poly => x"1021" -- CCITT16 ) PORT MAP( clk_sys => clk_sys, rst_n => rst_n, data => dat_crc, -- Dans le calcul du CRC, on prend en compte le flux déstuffé val => val_crc, init => init_crc, crc => crc ); end rtl;
Go to most recent revision | Compare with Previous | Blame | View Log